home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / AHDI606 / DRIVER.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  80.1 KB  |  2,512 lines

  1. ; July 31 1992 v6.00'
  2.  
  3. ;------------------------------------------------------------------------
  4. ;                                    :
  5. ;    AHDI Hard Disk Driver for the Atari ST, TT and ST Book        :
  6. ;    Copyright 1985-1991 Atari Corp.                    :
  7. ;    All Rights Reserved                        :
  8. ;                                    :
  9. ;------------------------------------------------------------------------
  10.  
  11.  
  12. ;+
  13. ; Conditional Assembly Switches
  14. ;-
  15. ospool        equ    1        ; increase size of OS pool for ROM
  16.  
  17.  
  18. ;
  19. ;+
  20. ; Edit History
  21. ;
  22. ;
  23. ; 22-May-1989    ml    Started this from ahdi 3.00
  24. ;            Files created for this driver:
  25. ;            ACSI.S        Low-level driver for ACSI.
  26. ;            CMDBLK.S    Builds packets for command blocks.
  27. ;            DOIT.S        Sends packets out to SCSI or ACSI.
  28. ;            DRIVER.S    This file.
  29. ;            SCSI.S        Low-level driver for SCSI.
  30. ;
  31. ; 25-May-1989    ml    Eliminated pread(), use _ahdi_rw() in physical mode
  32. ;            instead.
  33. ;
  34. ; 06-Jun-1989    ml    Created INSTALL.S for driver installation.
  35. ;
  36. ; 11-Jul-1989    ml    Rwabs() now handles DMA to fast RAM on ACSI side
  37. ;            also.  If no extra RAM was reserved for fast RAM
  38. ;            transferred, _dskbufp is used for the transfer.
  39. ;            (This is going to be really slow!!!)
  40. ;
  41. ; 19-Jul-1989    ml    If there is cache on CPU, Rwabs() reads will
  42. ;            flush both the I and D cache.
  43. ;
  44. ; 06-Sep-1989    ml    Use _FRB (in the cookie jar) for fast RAM transfer,
  45. ;            assuming _FRB WILL be there if there is fast RAM on
  46. ;            the machine.
  47. ;
  48. ; 20-Feb-1990    ml 3.64    Fixed bug in return code when doing ACSI odd transfer.
  49. ;            When successful, 0 should be returned.
  50. ;
  51. ; 02-Mar-1990    ml 3.65    Took out wait loop for SCSI 0 to be ready.
  52. ;            (modified file: install.s)
  53. ;
  54. ; 05-Mar-1990    ml 3.66    Added more checks for I/O to ACSI and SCSI non-
  55. ;            accessible memory.  _FRB will be used if it exists.
  56. ;            If _FRB doesn't exist, _dskbuf will used (which
  57. ;            means I/O could be "really" slow).  (_do_rw())
  58. ;
  59. ;            _FRB is being looked for when it's needed for the
  60. ;            first time, not at boot time.  (Applications can
  61. ;            add the _FRB when they are executed.)
  62. ;
  63. ; 08-Mar-1990    ml    Added SCFRDMA flag in defs.h to make SCSI DMA to 
  64. ;            fast RAM conditional assembly.
  65. ;            (modified file: driver.s)
  66. ;
  67. ; 15-Mar-1990    ml    Added DEBUG flag in defs.h to make debugging code
  68. ;            conditional assembly.
  69. ;
  70. ; 09-Apr-1990    ml 3.67    Added a "read" from WDL after toggling the ACSI DMA
  71. ;            chip to point the MMU to the correct direction.
  72. ;            (modified file: acsi.s)
  73. ;
  74. ; 10-Apr-1990    ml    Put up banner at beginning and end of loading driver
  75. ;            (requested by jwt), instead of just at the end.
  76. ;            (Printing of banner moved to install.s)
  77. ;
  78. ; 17-Apr-1990    ml    Added ODMA flag in defs.h to make the klutch of 
  79. ;            making byte counter bigger than # bytes requested
  80. ;            when receiving data from SCSI conditional assembly.
  81. ;            (modified file: scsi.s)
  82. ;
  83. ; 20-Apr-1990    ml    Added RDWDL flag in defs.h to make the "extra read"
  84. ;            added on 09-Apr-1990 conditional assembly.  (When
  85. ;            writing to ACSI, first 32 bytes are always FF's!!
  86. ;            Wondering why...)
  87. ;            (modified file: acsi.s)
  88. ;
  89. ; 30-Jul-1990    ml 4.00    Final for TT release. 
  90. ;            (Vectored-interrupts code not included)
  91. ;
  92. ; 31-Jul-1990    ml     Vectored-interrupt code included as conditional
  93. ;            assembly.
  94. ;
  95. ; 29-Oct-1990    ml 4.01    BUG!!!  Getcookie() module provided by AKP has a
  96. ;            variable declared in the bss.  This bss will be
  97. ;            clobbered when the driver adds GEMDOS buffers and
  98. ;            OS pool.  When getcookie() was called, and access 
  99. ;            the bss, it clobbered whatever was using its space
  100. ;            at the time.
  101. ;            Fixed in cookie.s by changing moving the variable
  102. ;            from the bss to the text segment.
  103. ;            (modified file: cookie.s)
  104. ;
  105. ; 26-Nov-1990    ml 4.02    BUG!!  From 3.00 through 4.01, when Rwabs() is called
  106. ;            in raw mode, it ignored media change completely.
  107. ;            This created problems with cartridge swapping on the 
  108. ;            removable drives.  If Getbpb(), on a logical drive 
  109. ;            that has not been accessed on the previous cartridge,
  110. ;            is called right after a cartridge swap, Getbpb() will
  111. ;            call Rwabs() in raw mode to read the partition map of
  112. ;            the physical unit concerned.  This Rwabs() call will
  113. ;            get the media change error from the controller and 
  114. ;            ignores it without setting any mcflg of the physical
  115. ;            unit.  Now when Mediach(), on a logical drive that was
  116. ;            accessed on the previous cartridge, is called, the 
  117. ;            driver will return media not change!
  118. ;            In version 4.02, Rwabs() still does not return media
  119. ;            change error when called in raw mode, but will 
  120. ;            remember it  by setting the mcflgs of the physical 
  121. ;            unit concerned to maybe changed.
  122. ;
  123. ; 02-Apr-1991    ml 4.03    BUG!!  At boot time, 
  124. ;                move.l    #(i_sasi1-i_sasi),tokeep 
  125. ;            is used to find number of bytes of code to keep.  
  126. ;            In pre-4.00 AHDI, this works just fine because both 
  127. ;            i_sasi1 and i_sasi are in the same file.  But, since 
  128. ;            3.00, i_sasi1 has been moved to the file INSTALL.S, 
  129. ;            thus external.  Madmac did not complain that the 
  130. ;            expression #(i_sasi1-i_sasi) is not valid anymore.  
  131. ;            Instead it assembles the code as
  132. ;                move.l    #i_sasi1,tokeep
  133. ;            This is bad, because it depends of where the driver 
  134. ;            is being loaded, the driver may end up hogging large
  135. ;            amount of memory that it is not using.  This is now
  136. ;            fixed by calculating the amount at run time.
  137. ;                move.l    #i_sasi1,tokeep 
  138. ;                subi.l    #i_sasi,tokeep
  139. ;            (modified file: driver.s)
  140. ;
  141. ; 04-Apr-1991    ml    Some SCSI drives will recalibrate every so often.
  142. ;            While recalibrating, the drive still accepts the
  143. ;            command block, but delays the transfer of data to 
  144. ;            after the recalibration.  So, timeout for the data
  145. ;            transfer should include the amount of time spent 
  146. ;            on recalibration.  The worst case we know of is
  147. ;            the Fujisu drives which takes 4 seconds.  So, the 
  148. ;            default for recalibration time is set to 4 seconds.
  149. ;            (modified files: driver.s, scsi.s)
  150. ;
  151. ; 08-Aug-1991    ml    BUG!!  When the eject button on the MEGAFILE 44 is
  152. ;            pressed without actually changing the cartridge, the
  153. ;            driver still thinks there is a media change.  The
  154. ;            driver complains that the FAT checksum is different
  155. ;            from what's been recorded.
  156. ;
  157. ;            The cause:
  158. ;                When _ahdi_rw() is called in physical mode, the
  159. ;            variable sizr should not be set.  First, it is not
  160. ;            necessary to set it, because the variable is not
  161. ;            used at all when in physical mode.  Secondly, the
  162. ;            setting of the variable overwrites its value which
  163. ;            may have been set by the logical mode _ahdi_rw() that
  164. ;            calls _ahdi_rw() recursively in physical mode!
  165. ;            (modified file: driver.s)
  166. ;
  167. ; 14-Aug-1991    ml 4.60    Folded v4.59, which handles the IDE drives, into 
  168. ;            v4.03.
  169. ;            (added files: ide.s, ide.h, blitter.h)
  170. ;            (modified files: driver.s, install.s, defs.h)
  171. ;            
  172. ; 19-Aug-1991    ml    Modified errcode() so that it returns a BIOS
  173. ;            error code instead of the controller error code.
  174. ;            It now handles error for ACSI, SCSI and IDE drives.
  175. ;
  176. ; 20-Aug-1991    ml    Optimized code by eliminating as many mulu's
  177. ;            and divu's as possible.
  178. ;            (modified files: driver.s install.s, acsi.s)
  179. ;
  180. ; 21-Aug-1991    ml    Modified the ACSI-accessible RAM boundary check
  181. ;            in _do_rw().  The boundary is at 4Mb for STs,
  182. ;            at 10Mb for TTs.
  183. ;            (modified files: driver.s, install.s, defs.h)
  184. ;
  185. ; 30-Aug-1991    ml    Eliminated the requirement that physical units 
  186. ;            connected to the system must have consecutive
  187. ;            physical unit numbers.  The flag how2scan tells
  188. ;            the driver how to scan the physical units.  If set,
  189. ;            the driver will scan the physical units as specified
  190. ;            by the flags to be explained later.  If how2scan is
  191. ;            not set, the driver will do the scanning the default
  192. ;            way, which is, consecutively.  Acsi2scan, scsi2scan
  193. ;            and ide2scan are flags introduced to tell the driver
  194. ;            which physical units to scan at boot time.  Each bit
  195. ;            in the flags corresponds to one physical unit.
  196. ;            acsi2scan: bit 0..7 corresponds to ACSI unit 0..7
  197. ;            scsi2scan: bit 0..7 corresponds to SCSI unit 0..7
  198. ;            ide2scan:  bit 0..1 corresponds to IDE  unit 0..1
  199. ;            Acsi2scan, scsi2scan and ide2scan are defaulted to
  200. ;            0xff, which tells the driver to scan all units.
  201. ;            (modified files: driver.s install.s)
  202. ;
  203. ; 06-Sep-1991    ml    Added boot-time-messages to show information of the
  204. ;            device being scanned.
  205. ;            (modified files: install.s)
  206. ;
  207. ; 13-Sep-1991    ml    Decision has been made that there will only be ONE
  208. ;            IDE drive connected to the controller at the current
  209. ;            IDE bus address.  So, code that was written to take
  210. ;            care of IDE unit 1 was eliminated.
  211. ;            (modified files: driver.s install.s)
  212. ;
  213. ; 16-Sep-1991    ml    Check if driver is running on ST Book.  If so, do
  214. ;            NOT use BLiTTER for IDE hard disk data transfer.
  215. ;            (modified files: driver.s install.s)
  216. ;
  217. ; 17-Sep-1991    ml    Added a flag, called ideinit, for programs (e.g. 
  218. ;            Slavik's POWER.PRG) to set to let the driver know 
  219. ;            that it needs to reinitialize the IDE drive.
  220. ;            Initializing the drive involves doing an identify(),
  221. ;            an initparm(), and reset of the drive's internal 
  222. ;            spin down counter.
  223. ;            (modified files: driver.s)
  224. ;
  225. ; 18-Sep-1991    ml    Assuming that an IDE drive will boot up in a mode as
  226. ;            specified by the parameters returned by the Identify
  227. ;            command, there is no need to do the Initparm command
  228. ;            at boot time.  There is also no need to reinitialize 
  229. ;            the drive after a shut down.  So changes added yes-
  230. ;            terday are deleted.
  231. ;            (modified files: driver.s install.s)
  232. ;
  233. ; 24-Sep-1991    ml 5.00a Wrapped up driver for ST Book and STE+.  To show 
  234. ;            info of ACSI devices at boot time, delay must be 
  235. ;            added to take care of the slow ones (e.g. laser 
  236. ;            printer.)
  237. ;            (modified files: acsi.s driver.s install.s)
  238. ;
  239. ; 01-Oct-1991    ml 5.00    First preliminary release for ST Book.
  240. ;
  241. ; 07-Oct-1991    ml    Changes made to _rcvacsi() in calculating # of 
  242. ;            times to send the command.  Refer to comments in
  243. ;            acsi.s.
  244. ;            (modified file: acsi.s)
  245. ;
  246. ; 11-Oct-1991    ml    Special-cased Conner CP2024 in finding current
  247. ;            drive parameters of IDE drives.
  248. ;            (modified files: ide.s install.s)
  249. ;            
  250. ; 22-Oct-1991    ml    Added in check for command line arguements.  If
  251. ;            there is any, do NOT print any messages on the
  252. ;            screen.
  253. ;            (modified files: driver.s install.s)
  254. ;
  255. ; 25-Nov-1991    ml 5.0a    Modified SCSI code to use the ACSI DMA chip.  This
  256. ;            limits the number of sectors that can be transferred
  257. ;            per command to the ACSI limit of 254 sectors.
  258. ;            (added files: spscsi.h spscsi.s)
  259. ;            (modified files: driver.s install.s)
  260. ;
  261. ; 10-Dec-1991    ml 5.0b    Fixed a couple of bugs.  Added memory boundary checks
  262. ;            for Sparrow.  Changed the way to test for IDE bus, 
  263. ;            access 0xf00010 instead of 0xf00000 (for now.)
  264. ;            (modified files: spscsi.s driver.s install.s)
  265. ;
  266. ; 12-Feb-1992    ml 5.0c    Modified _do_rw() to use the 14-bit counter on the
  267. ;            ACSI DMA chip of the Sparrow.
  268. ;            Modified _rcvspscsi() to utilize the "flush" bit in
  269. ;            the ACSI Mode Register.  This is not really needed
  270. ;            because the driver was doing programmed I/O for 
  271. ;            transfers fewer than 512 bytes.
  272. ;            (modified files: driver.s spscsi.s)
  273. ;
  274. ; 14-Feb-1992    ml    Added safety check in _resetspscsi().
  275. ;            (modified file: spscsi.s)
  276. ;
  277. ; 26-Feb-1992    ml 5.0d    Bug!  Modified check_dev() to support non-consecutive 
  278. ;            unit numbers.
  279. ;
  280. ; 03-Mar-1992    ml    Test if an IDE drive exists before sending it a 
  281. ;            command (even IDE bus exists.)
  282. ;            (modified file: driver.s ide.s install.s)
  283. ; 14-Apr-1992    ml    Slow down IDE non-BLiT transfers
  284. ;            (modified file: driver.s ide.s install.s)
  285. ; 31-Jul-1992    ml 6.00    Released version of the Falcon 030 driver.
  286. ; 25-Apr-1993    ers    Check for I/O past end of partition on logical
  287. ;            operations
  288. ;-
  289.  
  290.  
  291. .include    "defs.h"
  292. .include    "error.h"
  293. .include    "sysvar.h"
  294. .include    "68030.s"
  295. .include    "mfp.h"
  296. .include    "scsi.h"
  297. .include    "spscsi.h"
  298.  
  299.  
  300. .extern _untrdy
  301. .extern _rqsense
  302. .extern _hread
  303. .extern _hwrite
  304. .extern _xtdread
  305. .extern _xtdwrt
  306. .extern _ideread
  307. .extern _idewrite
  308. .extern _awto
  309. .extern    idexst
  310.  
  311. .extern    prnstr
  312.  
  313. .extern    i_sasi1
  314. .extern    _getcookie
  315. .extern    _drvxst
  316.  
  317. ;
  318. ;+
  319. ; Entry points:
  320. ;
  321. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  322. ;    +4   Boot entry point (from driver file off of C:)
  323. ;    +8   Reserved for future use
  324. ;    +$C  $F0AD magic number
  325. ;    +$E  version number
  326. ;    +$12 # chunks of ospool to add
  327. ;    +$14 # of sqnpart entries that follows
  328. ;    +$16 first sqnpart entry
  329. ;
  330. ; if bootloaded, d0 = # bytes allocated by boot code.
  331. ;-
  332. i_sasi:    bra    gboot            ; GEMDOS entry-point
  333.     bra    iboot            ; Boot entry-point
  334.     bra    iboot            ; (unused, reserved)
  335.  
  336.  
  337. ;+
  338. ;  Patchable variables
  339. ;-
  340. ; Published since v3.00
  341. magicnum:    dc.w    $f0ad        ; magic number to signify the
  342.                     ;  existence of  patchable variables
  343. vernum:        dc.w    $0500        ; AHDI version number
  344. numchunks:    dc.w    128        ; # chunks of memory to add to ospool
  345.         .globl    defbigsect
  346. defbigsect:    dc.w    512        ; default size of a big sector
  347. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  348.         .globl    defsqnpart    ; default # of logical drives
  349. defsqnpart:    dcb.b    MAXACSI,1    ;  reserved for removable ACSI units
  350. acsiidle:    dc.l    0        ; default idle time limit for ACSI
  351.                     ;  unit 0 (in # of _hz_200 ticks)
  352.  
  353. ; Published since v4.00:
  354. numsqcnpart:    dc.w    MAXSCSI        ; number of sqcnpart entries to follow
  355.         .globl    defsqcnpart    ; default # of logical drives
  356. defsqcnpart:    dcb.b    MAXSCSI,1    ;  reserved for removable SCSI units
  357.         .globl    scxltmout    
  358. scxltmout:    dc.l    12001        ; SCSI extra long-timeout (>1 min)
  359.         .globl    slwsclto    
  360. slwsclto:    dc.l    5000        ; SCSI stunit() long-timeout (>25s)
  361.         .globl    slwscsto    
  362. slwscsto:    dc.l    42        ; SCSI stunit() short-timeout (>205ms)
  363.         .globl    scltmout    
  364. scltmout:    dc.l    201        ; SCSI long-timeout (>1000 ms)
  365.         .globl    scstmout    
  366. scstmout:    dc.l    51        ; SCSI short-timeout (>500 ms)
  367.  
  368. ; Published since v4.03:
  369.         .globl    rcaltm    
  370. rcaltm:        dc.l    801        ; time for drive recalibration (>4s)
  371.  
  372. ; Published since v5.00:
  373.         .globl    ideidle        ; default idle time limit for IDE-IDE
  374. ideidle:    dc.w    0        ;  unit 0 (in 5 second increments)
  375.         .globl    how2scan    ; if set, scan physical units as
  376. how2scan:    dc.b    0        ;  specified by acsi/scsi/ide2scan
  377.         .globl    acsi2scan    ; bit mask of ACSI physical units
  378. acsi2scan:    dc.b    $ff        ;   to be scanned at boot time
  379.         .globl    scsi2scan    ; bit mask of SCSI physical units
  380. scsi2scan:    dc.b    $ff        ;   to be scanned at boot time
  381.         .globl    ide2scan    ; bit mask of IDE physical units
  382. ide2scan:    dc.b    $01        ;   to be scanned at boot time
  383.  
  384. ;+
  385. ; For Debugging 
  386.         .globl    badcombo    ; 
  387. badcombo:    dc.b    1        ; 1: combo is bad, don't use BLiTTER
  388. ;-
  389. .even
  390.  
  391.  
  392. ;+
  393. ; GEMDOS entry;
  394. ;   find amount of memory availble and store in d0.l
  395. ;-
  396. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  397.     move.b    $80(a2),silence        ; set flag for printing messages
  398.     move.l    4(a2),d0        ; d0 = available memory
  399.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  400.     sub.l    #$0100,d0
  401.     bra    i_sasi1            ; (continue with normal initialization)
  402.  
  403.  
  404. ;+
  405. ;  Boot entry;
  406. ;    set "bootloaded", record base address from boot loader, 
  407. ;    and continue with normal boot process.
  408. ;-
  409. iboot:    st    bootloaded        ; boot entry-point, set flag
  410.     sub.l    #$1c,d0            ; memory available -= file header
  411.     move.l    a2,baseaddr        ; install base address
  412.                     ; a2 = beginning addr of this block
  413.     bra    i_sasi1            ; (continue with normal initialization)
  414.  
  415.  
  416. ;
  417. ;+
  418. ; Driver State
  419. ;-
  420.         dc.b    13,'AHDI : July 31 1992 v6.00'
  421.         dc.b    13,10,$bd,'Atari Corp.'
  422.         dc.b    ' 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992'
  423.         dc.b    13,10,0,$1A
  424. .even
  425.  
  426. ;*****  Beginning Of Published Variables  *****
  427.  
  428.         .globl    puns
  429. puns:        dc.w    0        ; # of physical units on user's system
  430.  
  431. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  432.         .globl    pun
  433. pun:        dcb.b    MAXLOG,0    ; physical unit table
  434. .even
  435.  
  436. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  437.         .globl    start
  438. start:        dcb.l    MAXLOG,0    ; partition start table
  439.  
  440.         .globl    cookie        ; *** DON'T CHANGE ***
  441. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  442.  
  443.         .globl    cookptr
  444. cookptr:    dc.l    0        ; pointer to cookie
  445.  
  446. versn:        dc.w    $0600        ; version number: MMmm
  447.  
  448.         .globl    maxssz
  449. maxssz:        dc.w    512        ; maximum sector size allowed
  450.  
  451. acsisd:        dc.l    0        ; idle time limit to spin down ACSI 
  452.                     ; unit 0 (applicable to STACY ONLY)
  453.         .globl    idesd        ; idle time limit to spin down
  454. idesd:        dc.w    0        ; IDE unit 0 
  455.  
  456.         dcb.w    29,0        ; reserved for future use
  457.  
  458. ;*****  End Of Published Variables  *****
  459.  
  460.         .globl    numacsi
  461. numacsi:    dc.w    0        ; number of ACSI drives
  462.  
  463.         .globl    numscsi
  464. numscsi:    dc.w    0        ; number of SCSI drives
  465.  
  466.     .globl    mcflgs
  467. mcflgs:    dcb.b    MAXLOG,2        ; media change flag table
  468.     .globl    xst
  469. xst:    dcb.b    MAXLOG,1        ; drive existence flag table
  470.     .globl    idedp
  471. idedp:    dcb.b    IDEDPLEN,0        ; IDE drive parameters table
  472. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  473. serno:    dcb.b    MAXLOG*SERLEN,0        ; serial number table
  474.     .globl    sratio
  475. sratio:    dcb.b    MAXLOG,1        ; log sect size : phys sect size tbl
  476. fatsum:    dcb.b    MAXLOG<<FATLEN,0    ; FAT checksum table
  477. fatst:    dcb.w    MAXLOG,0        ; starting sector # of last FAT
  478. fatend:    dcb.w    MAXLOG,0        ; ending sector # of last FAT
  479.  
  480.         .globl    bootloaded
  481. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  482.         .globl    memalloc
  483. memalloc:    dc.l    0        ; total memory available if bootloaded
  484. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  485. tokeep:        dc.l    0        ; amount memory to keep
  486.  
  487.         .globl    machine        ; value of _MCH
  488. machine:    dc.l    0        ; high word is machine type
  489.  
  490.         .globl    cpun
  491. cpun:        dc.w    0        ; current physical unit
  492.         .globl    npart
  493. npart:        dc.w    0        ; number of partitions found
  494. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  495.  
  496. strec:        dc.l    0        ; starting sector to read/write
  497. endrec:        dc.l    0        ; last sector to read/write
  498. stbuf:        dc.l    0        ; starting address of buffer
  499.         .globl    embscsi
  500. embscsi:    dc.b    0        ; 1: embedded SCSI drive
  501.  
  502. frbbuf:        dc.l    0        ; pointer to _FRB
  503.  
  504. _retries:    dc.w    NRETRIES    ; number of retries to do
  505. retrycnt:    dc.w    1        ; retry counter
  506.  
  507.         .globl    o_bpb
  508. o_bpb:        dc.l    1        ; old bpb vector
  509.         .globl    o_rw
  510. o_rw:        dc.l    1        ; old rwabs vector
  511.         .globl    o_mediach
  512. o_mediach:    dc.l    1        ; old media change vector
  513.  
  514.         .globl    sendata
  515. sendata:    dcb.b    32,0        ; buffer for sense data
  516.  
  517. lastmdctm:    dc.l    0        ; time media change was last called
  518.         .globl    pbuf
  519. pbuf:        dc.l    0        ; ptr to start of root sector image
  520. fsiz:        dc.w    0        ; FAT size in sectors
  521. fatrec:        dc.w    0        ; 2nd FAT starting sector
  522.         .globl    sizr
  523. sizr:        dc.w    1        ; ratio of log : phys sector size
  524. cstart:        dc.l    0        ; current dev's starting sector
  525. csize:        dc.l    0        ; current dev's num. of sectors
  526. temp:        dc.l    0        ; temporary storage
  527.         .globl    partsize
  528. partsize:    dcb.l    MAXLOG,0    ; partition size table
  529.                     ; (size is in logical sectors)
  530.         .globl    savssp
  531. savssp:        dc.l    1        ; (saved SSP)
  532.         .globl    _cachexst
  533. _cachexst:    dc.b    0        ; 0: no cache    1: with cache
  534.         .globl    _useblit
  535. _useblit:    dc.b    0        ; 0: don't BLiT IDE hard disk data
  536.         .globl    ext
  537. ext:        dc.b    0        ; if =0, not processing ext partition
  538.         .globl    extrt
  539. extrt:        dc.l    0        ; starting sector of ext DOS partition
  540.         .globl    extvol
  541. extvol:        dc.l    0        ; offset wrt ext DOS partition
  542. pbpb:        dc.w    0        ; partition # for dev
  543.         .globl    silence
  544. silence:    dc.b    0        ; 0: print messages
  545.         .globl    _spscsixst    
  546. _spscsixst:    dc.b    0        ; 0: no Sparrow SCSI
  547. .even
  548.  
  549.  
  550. ;
  551. ;+
  552. ; Front End
  553. ;-
  554.  
  555. ;+
  556. ;  Return pointer to BPB (or NULL)
  557. ;
  558. ;    Synopsis:    LONG hbpb(dev)
  559. ;        WORD dev;    4(sp).w
  560. ;-
  561.     .globl    hbpb
  562. hbpb:    move.w    4(sp),d0        ; d0 = devno
  563.     clr    d1            ; d1 = 0, physical op not possible
  564.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  565.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  566.     bra.s    check_dev        ; do it
  567.  
  568.  
  569. ;+
  570. ;  Read or write logical sectors
  571. ;
  572. ;    Synopsis:    LONG hrw(rw, buf, count, recno, dev)
  573. ;        WORD rw;    $4(sp).w
  574. ;        char *buf;    $6(sp).l
  575. ;        WORD count;    $a(sp).w
  576. ;        WORD recno;    $c(sp).w
  577. ;        WORD dev;    $e(sp).w
  578. ;-
  579.     .globl    hrw
  580. hrw:    move.w    $e(sp),d0        ; d0 = devno
  581.     move.w    4(sp),d1        ; d1 includes physical device flag
  582.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  583.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  584.     bra.s    check_dev        ; do it
  585.  
  586.  
  587. ;+
  588. ;  Check for media change
  589. ;
  590. ;    Synopsis:    LONG hmediach(dev)
  591. ;        WORD dev;    4(sp).w
  592. ;-
  593.     .globl    hmediach
  594. hmediach:
  595.     move.w    4(sp),d0        ; d0 = devno
  596.     clr    d1            ; physical operation not possible
  597.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  598.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  599.  
  600.  
  601. ;+
  602. ;  check_dev - use handler, or pass vector through
  603. ;
  604. ;  Passed:    d0.w = device#
  605. ;        d1, bit 3  1=physical operation
  606. ;        a0 ->  old handler
  607. ;        a1 ->  new handler
  608. ;        a5 ->  $0000 (zero-page ptr)
  609. ;
  610. ;  Jumps-to:    (a1) if dev in range for this handler
  611. ;        (a0) otherwise
  612. ;-
  613. check_dev:
  614.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  615.     bmi.s    chkd_f            ; if lower, not one of ours
  616.  
  617.     btst    #3,d1            ; is this a physical unit operation?
  618.     beq.s    chkd_a            ; if not, go check against pun
  619.                     ; else check existence of phys unit
  620.     cmp.w    #ACSIUNT,d0        ; an ACSI unit?
  621.     bgt.s    chkd_sc            ; if not, try SCSI
  622.     tst.w    numacsi            ; any ACSI unit connected?
  623.     bne.s    chkd_s            ; if so, it's one of ours
  624. chkd_sc:                ; else
  625.     cmp.w    #SCSIUNT,d0        ; an SCSI unit?
  626.     bgt.s    chkd_ide        ; if not, try IDE
  627.     tst.w    numscsi            ; any SCSI unit connected?
  628.     bne.s    chkd_s            ; if so, it's one of ours
  629. chkd_ide:                ; else
  630.     cmp.w    #IDEUNT,d0        ; an IDE unit?
  631.     bgt.s    chkd_f            ; if not, not one of ours
  632.     move.w    puns,d1            ; d1.w = number of valid IDE units
  633.     sub.w    numacsi,d1        ;      = total -  #ACSI - #SCSI
  634.     sub.w    numscsi,d1
  635.     tst.w    d1            ; any IDE unit connected?
  636.     bne.s    chkd_s            ; if so, it IS one of of ours
  637.     bra.s    chkd_f            ; else not one of ours
  638.  
  639. chkd_a:    
  640.  
  641. ;+
  642. ; Aug-08-91 ml.    Added upper bound check for logical device #
  643. ;
  644.     cmp.w    #MAXLOG,d0        ; if logical device # >= MAXLOG
  645.     bge.s    chkd_f            ; it's not one of ours
  646. ;-
  647.     lea    pun,a2            ; pointer to pun map
  648.     tst.b    0(a2,d0.w)        ; must be positive for a real unit
  649.     bmi.s    chkd_f
  650. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  651. chkd_f:    jmp    (a0)            ; do it
  652.  
  653.  
  654. ;
  655. ;+
  656. ; Medium-Level Driver
  657. ;-
  658.  
  659. ;+
  660. ; Return BPB for logical device
  661. ;
  662. ; Synopsis:    LONG _sasi_bpb(dev)
  663. ;        WORD dev;    $4(sp).w
  664. ;
  665. ; Returns:    NULL, or a pointer to the BPB buffer
  666. ;
  667. ; 10-21-88    ml.    I am not making a special case for non-removable
  668. ;            hard disk, because if a program uses Allan's
  669. ;            program to force a media change, the program 
  670. ;            should be getting the "Real" AND "New" BPB.
  671. ;            (The old (v1.7 and before) AHDI only index into
  672. ;            the bpbs table and return the pointer, without
  673. ;            actually go and read the boot sector of the dev.)
  674. ;-
  675. _sasi_bpb:
  676.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  677.     move.w    4(sp),d1        ; d1 = device number
  678.     lea    pun,a0            ; a0 -> pun table
  679.     adda.w    d1,a0            ; a0 -> pun @ dev's entry
  680.     moveq    #0,d2            ; coerce byte to word
  681.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  682.     move.w    d2,cpun            ; cpun = pun(dev)
  683.  
  684.     lea    xst,a1            ; a1 -> drive existence table
  685.     tst.b    (a1,d1.w)        ; does drive exist?
  686.     bne.s    bpbgo            ; if it does, go on normally
  687.                     ; else, see if it really doesn't exist
  688.     movem.l    d1/a0,-(sp)        ; save registers
  689.     move.w    d2,-(sp)        ; physical unit number
  690.     bsr    _untrdy            ; verify by doing test unit ready
  691.     addq.l    #2,sp            ; cleanup stack
  692.     movem.l    (sp)+,d1/a0        ; restore registers
  693.     tst.w    d0            ; return good status?
  694.     beq    badbpb            ; if yes, ie. medium has not changed
  695.                     ; therefore, dev still doesn't exist
  696.     moveq    #1,d0            ; else medium may have changed
  697.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  698.                     ; and go try to get BPB
  699. bpbgo:    move.l    _dskbufp,pbuf        ; pbuf -> 2nd half of 1K disk buf
  700.     add.l    #512,pbuf
  701.  
  702. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  703.     move.w    cpun,-(sp)        ; physical unit number
  704.     addq.w    #2,(sp)            ; unit # including A: and B:
  705.     clr.w    -(sp)            ; from sector 0
  706.     move.w    #1,-(sp)        ; read in 1 sector
  707.     move.l    pbuf,-(sp)        ; buffer to read into
  708.     move.w    #$a,-(sp)        ; in phys mode/ignore media change
  709.     bsr    _ahdi_rw        ; ahdi_rw($a, pbuf, 1, 0, cpun)
  710.     adda    #12,sp
  711.     movea.l    (sp)+,a0        ; restore ptr to pun(dev)
  712.     tst    d0            ; read successful?
  713.     beq.s    bpb0            ; if yes, go on normally
  714.                     ; else call up error handler
  715. bpberr:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  716.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  717.     bsr    critic            ; call up critical error handler
  718.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  719.     cmpi.l    #CRITRETRY,d0        ; retry?
  720.     beq.s    bpb00            ; if so, go and try again
  721.     bra    badbpb            ; else return no BPB
  722.  
  723. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  724.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  725. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  726.     bne.s    bpb2
  727.     addq.w    #1,pbpb
  728.     bra.s    bpb1
  729.  
  730. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  731.     movea.l    pbuf,a0            ; a0 -> beginning of root sector
  732.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  733.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  734.     bsr    dosbpb            ; else, handle it the DOS way
  735.     bra.s    bpb4            ; else, go get the bpb
  736. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  737.     bsr    gembpb            ; handle it the GEMDOS way
  738. bpb4:    tst.w    d0            ; successful?
  739.     beq.s    bpbnf            ; if =0, no valid BPB found
  740.     bpl.s    bpb5            ; if +ive, valid BPB found
  741.     bra.s    badbpb            ; else no BPB found
  742.                     ; partition not found
  743. bpbnf:    lea    xst,a0            ; a0 -> drive existence table
  744.     move.w    4(sp),d0        ; d0 = dev number
  745.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  746.     lea    mcflgs,a0        ; a0 -> mcflgs table
  747.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  748.     bra.s    badbpb            ; can't find such a partition
  749.  
  750. bpb5:    move.l    d1,-(sp)        ; start_sector
  751.     move.w    8(sp),-(sp)        ; dev number
  752.     bsr    getbpb            ; getbpb(dev, start_sector)
  753.     addq.l    #6,sp            ; clean up stack
  754.     tst.l    d0            ; getbpb successful?
  755.     bpl.s    retbpb            ; if so, return ptr to bpb
  756. badbpb:    moveq    #0,d0            ; return no bpb found
  757. retbpb:    rts
  758.  
  759.  
  760. ;
  761. ;+
  762. ; dosbpb - find the DOS partition that corresponds to the requested
  763. ;       logical drive
  764. ; Passed:
  765. ;    a0 = buffer address for root sector
  766. ;    d1 = number of entries in partition map
  767. ;
  768. ; Assumed:
  769. ;    pbpbs = partition being looked for
  770. ;
  771. ; Returns:
  772. ;    d0.b = 0        if partition not found
  773. ;         = negative #    some kind of error
  774. ;         = positive #    system indicator of the partition
  775. ;    d1.l = starting sector of the partition (if it is found)
  776. ;-
  777. dosbpb:    adda.w    #DOSPM,a0        ; a0 -> partition map
  778. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  779.     sf    ext            ; not dealing with ext partition
  780.     bsr    fdpart            ; find a partition
  781.     tst.b    d0            ; found any?
  782.     beq.s    dbpba            ; not a valid partition
  783.     cmpi.b    #5,d0            ; extended partition?
  784.     bne.s    dbpb1            ; if not, it's a regular partition
  785.     st    ext            ; else, it's an extended partition
  786.     move.l    #0,extvol        ; offset from start of partition = 0
  787.     move.l    d1,extrt        ; starting sector # of ext partition
  788. dbpbx:    bsr    fdnxt            ; find next logical drive
  789.     tst.b    d0            ; found any?
  790.     beq.s    dbpba            ; no logical drive found
  791.     bmi.s    dbpb2            ; error returned
  792.     cmpi.b    #5,d0            ; extended volume?
  793.     beq.s    dbpbx            ; if so, go find next logical drive
  794. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  795.     bpl.s    dbpb3            ; if not, continue the search
  796. dbpb2:    addq.l    #8,sp            ; else clean up stack
  797.     move.w    #0,bfat            ; assume partition has 12-bit fat
  798.     cmpi.b    #1,d0            ; 12-bit fat?
  799.     beq.s    dbpb22            ; if so, return
  800.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  801. dbpb22:    bra.s    dbpbr            ; and return
  802. dbpb3:    tst.b    ext            ; clun is in ext partition?
  803.     bne.s    dbpbx            ; if so, go find next ext vol
  804. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  805.     adda    #16,a0            ; index to next entry in pmap
  806.     dbra    d1,dbpb0
  807.     moveq    #0,d0            ; partition not found!
  808. dbpbr:    rts
  809.  
  810.     
  811. ;+
  812. ; fdpart - find a DOS partition.
  813. ;
  814. ; Passed:
  815. ;    a0 = address to partition entry
  816. ;
  817. ; Returns:
  818. ;    d0.b = 0        partition is not valid
  819. ;         = positive    #    partition is a valid partition
  820. ;           (this is the system indicator of the partition)
  821. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  822. ;         = starting sector # of extended partition (if d0.b = 5)
  823. ;-
  824.     .globl    fdpart
  825. fdpart:    tst.l    12(a0)            ; partition's size?
  826.     beq.s    fdp0            ; if =0, not valid
  827.  
  828.     move.b    4(a0),d0        ; d0 = system indicator
  829.     beq.s    fdpr            ; if =0, not valid
  830.  
  831.     cmpi.b    #4,d0            ; if =4, valid
  832.     beq.s    fdp1
  833.  
  834.     cmpi.b    #1,d0            ; if =1, valid
  835.     beq.s    fdp1
  836.  
  837.     cmpi.b    #5,d0            ; if =5, valid
  838.     beq.s    fdp1
  839.  
  840. fdp0:    moveq    #0,d0            ; else, not valid
  841.     bra.s    fdpr
  842.  
  843. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  844.     ror.w    #8,d1            ; swap hi and lo byte of high word
  845.     swap    d1            ; swap hi and lo word
  846.     ror.w    #8,d1            ; swap hi and lo byte of low word
  847. fdpr:    rts
  848.  
  849.  
  850. ;+
  851. ; fdnxt - find a logical drive in the extended DOS partition
  852. ;
  853. ; Passed:
  854. ;    d0.b = (= 5 if a new extended volume was found)
  855. ;           (= 0 if nxtdrv was successful for last logical drive found)
  856. ;    d1.l = starting sector # of this extended volume
  857. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  858. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  859. ;
  860. ; Assumes:
  861. ;    cpun = current physical unit #
  862. ;    extrt = starting sector # of extended DOS partition
  863. ;    extvol = offset from start of extended DOS partition (in sectors)
  864. ;
  865. ; Returns:
  866. ;    d0.b = 0        no logical drive found
  867. ;         = positive #    valid logical drive found
  868. ;           (this is the system indicator of the logical drive)
  869. ;         = negative #    error occured
  870. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  871. ;         = starting sector # of next extended volume (if d0.b = 5)
  872. ;-
  873.     .globl    fdnxt
  874. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  875.     bne.s    fdnxt0        ; if not, search for one
  876.     move.l    d1,-(sp)    ; from beginning of extended volume
  877.     move.w    cpun,-(sp)    ; physical unit number
  878.     addq.w    #2,(sp)        ; unit # including A: and B:
  879.     move.w    #-1,-(sp)    ; using a long sector number
  880.     move.w    #1,-(sp)    ; read in 1 sector
  881.     move.l    _dskbufp,-(sp)    ; buffer to read into
  882.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  883.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  884.     adda    #16,sp        ; cleanup stack
  885.     tst.w    d0        ; read successful?
  886.     bne    fdnxtr        ; if not, return
  887.     
  888.     movea.l    _dskbufp,a0    ; else, 
  889.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  890.     bne.s    fdnxtr        ; if not, return no drive found
  891.                 ; (d0 already set by ahdi_rw)
  892.     adda.w    #DOSPM-16,a0    ; a0 -> 1st entry in log drive map
  893.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  894.  
  895. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  896.     bmi.s    fdnxt1        ; if not, return
  897.  
  898.     adda    #16,a0        ; a0 -> entry to be examined
  899.     tst.l    12(a0)        ; partition size's?
  900.     beq.s    fdnxt0        ; if =0, not valid
  901.  
  902.     move.b    4(a0),d0    ; d0 = system indicator
  903.     beq.s    fdnxt0        ; if =0, not valid
  904.  
  905.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  906.     beq.s    fdnxt0        ; if =0, not valid
  907.     ror.w    #8,d1        ; swap hi and lo byte of high word
  908.     swap    d1        ; swap hi and lo word
  909.     ror.w    #8,d1        ; swap hi and lo byte of low word
  910.  
  911.     cmpi.b    #4,d0        ; if =4,
  912.     beq.s    fdnxt2        ; valid logical drive found
  913.  
  914.     cmpi.b    #1,d0        ; if =1,
  915.     beq.s    fdnxt2        ; valid logical drive found
  916.  
  917.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  918.     bne.s    fdnxt0        ; else, not valid
  919.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  920.     bra.s    fdnxt3
  921.  
  922. fdnxt1:    moveq    #0,d0        ; return no drive found
  923.     bra.s    fdnxtr
  924.  
  925. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  926. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  927. fdnxtr:    rts
  928.  
  929.  
  930. ;
  931. ;+
  932. ; gembpb - find the GEMDOS partition that corresponds to the requested
  933. ;       logical drive.
  934. ; Passed:
  935. ;    a0 = buffer address for root sector
  936. ;    d1 = number of entries in partition map
  937. ;
  938. ; Assumed:
  939. ;    pbpbs = partition being looked for
  940. ;
  941. ; Returns:
  942. ;    d0.b = 0        if partition not found
  943. ;         = negative #    some kind of error
  944. ;         = positive #    system indicator of the partition
  945. ;    d1.l = starting sector of the partition (if it is found)
  946. ;-
  947. gembpb:    adda.w    #HDSIZ,a0        ; a0 -> hard disk size
  948.     tst.l    (a0)+            ; size? (a0 -> start of pmap)
  949.     beq.s    gbpb4            ; if =0, no drive will exist
  950. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  951.     sf    ext            ; not dealing with ext partition
  952.     bsr    fgpart            ; find partitions
  953.     tst.b    d0            ; found any?
  954.     beq.s    gbpba            ; not a valid partition
  955.     cmpi.b    #'X',d0            ; extended partition?
  956.     bne.s    gbpb1            ; if not, it's a regular partition
  957.     st    ext            ; else, it's an extended partition
  958.     move.l    #0,extvol        ; offset from start of partition = 0
  959.     move.l    d1,extrt        ; starting sector # of ext partition
  960. gbpbx:    bsr    fgnxt            ; find next logical drive
  961.     tst.b    d0            ; found any?
  962.     beq.s    gbpba            ; no logical drive found
  963.     bmi.s    gbpb2            ; error returned
  964.     cmpi.b    #'X',d0            ; extended volume?
  965.     beq.s    gbpbx            ; if so, go find next logical drive
  966. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  967.     bpl.s    gbpb3            ; if not, continue the search
  968. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  969.     bra.s    gbpbr            ; and return
  970. gbpb3:    tst.b    ext            ; clun is in ext partition?
  971.     bne.s    gbpbx            ; if so, go find next ext vol
  972. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  973.     adda    #12,a0            ; index to next entry in pmap
  974.     dbra    d1,gbpb0
  975. gbpb4:    moveq    #0,d0            ; partition not found!
  976. gbpbr:    rts
  977.  
  978.  
  979. ;+
  980. ; fgpart - find a GEMDOS partition.
  981. ;
  982. ; Passed:
  983. ;    a0 = address to partition entry
  984. ;
  985. ; Returns:
  986. ;    d0.b = 0        partition is not valid
  987. ;         = positive    #    partition is a valid partition
  988. ;           (this is the first byte in p_id of the partition)
  989. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  990. ;         = starting sector # of extended partition (if d0.b = 'X')
  991. ;-
  992.     .globl    fgpart
  993. fgpart:    tst.b    (a0)            ; check the valid partition flag
  994.     beq.s    fgp2            ; if =0, not valid
  995.  
  996.     tst.l    8(a0)            ; partition's size?
  997.     beq.s    fgp2            ; if =0, not valid
  998.  
  999.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  1000.     bne.s    fgp0            ; for REGULAR partition
  1001.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  1002.     bne.s    fgp0
  1003.     cmpi.b    #'M',3(a0)
  1004.     beq.s    fgp3
  1005.  
  1006. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  1007.     bne.s    fgp1            ; for BIG partition
  1008.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  1009.     bne.s    fgp1
  1010.     cmpi.b    #'M',3(a0)
  1011.     beq.s    fgp3
  1012.  
  1013. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  1014.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  1015.     cmpi.b    #'G',2(a0)        ; partition
  1016.     bne.s    fgp2            ; (ie., partition with
  1017.     cmpi.b    #'M',3(a0)        ;  a linked list of
  1018.     beq.s    fgp3            ;  logical drives)
  1019.  
  1020. fgp2:    moveq    #0,d0            ; else, not valid
  1021.     bra.s    fgpr
  1022.  
  1023. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  1024.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  1025. fgpr:    rts
  1026.  
  1027.  
  1028. ;+
  1029. ; fgnxt - find a logical drive in the extended GEMDOS partition
  1030. ;
  1031. ; Passed:
  1032. ;    d0.b = (= 'X' if a new extended volume was found)
  1033. ;           (= 0 if nxtdrv was successful for last logical drive found)
  1034. ;    d1.l = starting sector # of this extended volume
  1035. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  1036. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  1037. ;
  1038. ; Assumes:
  1039. ;    cpun = current physical unit #
  1040. ;    extrt = starting sector # of extended GEMDOS partition
  1041. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  1042. ;
  1043. ; Returns:
  1044. ;    d0.b = 0        no logical drive found
  1045. ;         = positive #    valid logical drive found
  1046. ;           (this is the first byte of p_id of the logical drive)
  1047. ;         = negative #    error occured
  1048. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  1049. ;         = starting sector # of next extended volume (if d0.b = 'X')
  1050. ;-
  1051.     .globl    fgnxt
  1052. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  1053.     bne.s    fgnxt0        ; if not, search for one
  1054.     move.l    d1,-(sp)    ; from beginning of extended volume
  1055.     move.w    cpun,-(sp)    ; physical unit number
  1056.     addq.w    #2,(sp)        ; unit # including A: and B:
  1057.     move.w    #-1,-(sp)    ; using a long sector number
  1058.     move.w    #1,-(sp)    ; read in 1 sector
  1059.     move.l    _dskbufp,-(sp)    ; buffer to read into
  1060.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1061.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsectno)
  1062.     adda    #16,sp        ; cleanup stack
  1063.     tst.w    d0        ; read successful?
  1064.     bne    fgnxtr        ; if not, return error
  1065.  
  1066.     movea.l    _dskbufp,a0    ; a0 -> partition map
  1067.     adda.w    #HDSIZ+4-12,a0    ; a0 -> 1st entry in log drive map
  1068.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  1069.  
  1070. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  1071.     bmi.s    fgnxt3        ; if not, return
  1072.  
  1073.     adda    #12,a0        ; a0 -> entry to be examined
  1074.     tst.l    8(a0)        ; partition size's?
  1075.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  1076.  
  1077.     tst.b    (a0)        ; check the valid partition flag
  1078.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  1079.  
  1080.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  1081.  
  1082.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  1083.     bne.s    fgnxt1        ; for REGULAR partition
  1084.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  1085.     bne.s    fgnxt1
  1086.     cmpi.b    #'M',3(a0)
  1087.     beq.s    fgnxt4
  1088.  
  1089. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  1090.     bne.s    fgnxt2        ; for BIG partition
  1091.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  1092.     bne.s    fgnxt2
  1093.     cmpi.b    #'M',3(a0)
  1094.     beq.s    fgnxt4
  1095.  
  1096. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  1097.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  1098.     cmpi.b    #'G',2(a0)    ; partition
  1099.     bne.s    fgnxt3        ; (ie., partition with
  1100.     cmpi.b    #'M',3(a0)    ;  a linked list of
  1101.     bne.s    fgnxt0        ;  logical drives)
  1102.  
  1103.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  1104.     bra.s    fgnxt5
  1105.  
  1106. fgnxt3:    moveq    #0,d0        ; return no drive found
  1107.     bra.s    fgnxtr
  1108.  
  1109. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  1110. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  1111.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  1112. fgnxtr:    rts
  1113.  
  1114.  
  1115. ;
  1116. ;+
  1117. ; getbpb(dev, sectorno)
  1118. ; WORD dev;        4(sp).w
  1119. ; LONG sectorno;    6(sp).l
  1120. ;
  1121. ; Assume -
  1122. ;    cpun contains physical unit number of dev
  1123. ;-
  1124. getbpb:    move.l    $6(sp),-(sp)    ; sector # of boot sector
  1125.     move.w    cpun,-(sp)    ; physical unit
  1126.     addq.w    #2,(sp)        ; unit # including A: and B:
  1127.     move.w    #-1,-(sp)    ; using a long sector number
  1128.     move.w    #1,-(sp)    ; 1 sector
  1129.     move.l    _dskbufp,-(sp)    ; buffer
  1130.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1131.     bsr    _ahdi_rw    ; ahdi_rw(8, buf, 1, -1, cpun, lsectno)
  1132.     adda    #16,sp        ; clean up stack
  1133.     tst.w    d0        ; successful?
  1134.     beq.s    getb0        ; if so, go on normally
  1135.                 ; else let user retry
  1136. getb9:    move.w    4(sp),d1    ; d1 = drive # excluding A: and B:
  1137.     bsr    critic
  1138.     cmpi.l    #CRITRETRY,d0    ; retry?
  1139.     bne    getb7        ; if not, return
  1140.     bra.s    getbpb        ; else read again
  1141.  
  1142. getb0:    movea.l    _dskbufp,a0    ; a0 -> boot sector image
  1143.     movea.l    #bpbs,a2    ; a2 -> bpb
  1144.  
  1145.     move.w    #$0b,d0
  1146.     bsr    getlhw
  1147.     cmp.w    maxssz,d0    ; is sector size too big?
  1148.     bhi    getb7        ; if it is, can't handle it
  1149.     move.w    d0,(a2)+    ; =byt/sec
  1150.     beq    getb7        ; if =0, bad data
  1151.     move.w    d0,d1        ; d1 = logical sector size
  1152.     moveq    #9,d2        ; d0.b = (log : phys) sector size ratio
  1153.     lsr.w    d2,d0        ;      = logical sector size / 512
  1154.     move.w    d0,sizr        ; save the ratio
  1155.  
  1156.     clr.w    d0
  1157.     move.b    $d(a0),d0
  1158.     move.w    d0,(a2)+    ; = #sectors/cluster
  1159.     beq    getb7        ; if =0, bad data
  1160.  
  1161.     mulu    d1,d0
  1162.     move    d0,(a2)+    ; = #bytes/cluster
  1163.  
  1164.     moveq    #$11,d0
  1165.     bsr    getlhw        ; number of directory entries
  1166.     tst    d0        ; num o' entries ?= 0
  1167.     beq    getb7        ; if so, bad data
  1168.      lsl.l    #5,d0        ; size root dir = (32 * num entries) bytes
  1169.     divu    d1,d0        ; number of sectors required
  1170.     move.l    d0,d1
  1171.     swap    d1
  1172.     tst    d1
  1173.     beq.s    getb1
  1174.     addq    #1,d0        ; round up
  1175. getb1:    move    d0,(a2)+    ; =rdlen
  1176.     move    d0,d2
  1177.  
  1178.     move    #$16,d0
  1179.     bsr    getlhw
  1180.     move    d0,(a2)+    ; =FATsize
  1181.     beq    getb7        ; if =0, bad data
  1182.     move    d0,d1
  1183.     move    d0,fsiz        ; save FAT size
  1184.  
  1185.     move    #$e,d0
  1186.     bsr    getlhw        ; number of reserved sectors
  1187.     add    d1,d0
  1188.     move    d0,(a2)+    ; =2nd FAT start
  1189.     move    d0,fatrec    ; save 2nd FAT start 
  1190.  
  1191.     add    d1,d0        ; plus size of second fat
  1192.     add    d2,d0        ; plus rdlen
  1193.     move    d0,(a2)+    ; = data start
  1194.     move    d0,d2        ; save start of data
  1195.  
  1196.     move    #$13,d0
  1197.     bsr    getlhw        ; number of sectors on media
  1198.     move    d0,csize+2    ; save it for later use...
  1199.     sub    d2,d0        ; subtract # used by FATs,dir,boot
  1200.     beq    getb7        ; if =0, bad data
  1201.     clr.l    d1
  1202.     move    d0,d1
  1203.     clr    d0
  1204.     move.b    $d(a0),d0    ; number of sectors/cluster
  1205.     divu    d0,d1        ; rounding down
  1206.     move    d1,(a2)+    ; =number of clusters
  1207.     move    bfat,(a2)    ; =flags, 12 or 16 bit fats
  1208.  
  1209.     move.w    sizr,d2        ; d2 = current sector size ratio
  1210.     lea    sratio,a1    ; a1 -> sector size ratio table
  1211.     move.w    4(sp),d0    ; d0 = drive number
  1212.     move.b    d2,(a1,d0.w)    ; update sector size ratio in table
  1213.  
  1214.     btst.b    #6,cpun+1    ; is unit removable?
  1215.     beq    getb6        ; if not, can skip the fat checksum
  1216.  
  1217.     lea    serno,a1    ; a1 -> table of serial #s
  1218.     mulu.w    #SERLEN,d0    ; dev# * SERLEN to index into table
  1219.     adda.l    d0,a1        ; a1 -> serial # of dev
  1220.     move.w    #SERLEN-1,d1    ; length of serial # - 1
  1221. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1222.     dbra    d1,getb2
  1223.  
  1224.     lea    fatsum,a2    ; a2 -> FAT check sum table
  1225.     moveq    #0,d0        ; coerce to long
  1226.     move.w    4(sp),d0    ; d0 = dev number
  1227.     lsl.l    #FATLEN,d0    ; d0 << FATLEN = to index into table
  1228.     adda.l    d0,a2        ; a2 -> FAT check sum tbl of dev
  1229.  
  1230.     move.w    fatrec,d0    ; d0 = log starting sector of 2nd FAT
  1231.     mulu    d2,d0        ; (in 512-byte sectors)
  1232.     movea.l    $6(sp),a1    ; a1 = starting sector of drive
  1233.     adda.l    d0,a1        ; a1 = phys starting sector of 2nd FAT
  1234.  
  1235.     move.w    fsiz,d1        ; d1 = # FAT sectors to read
  1236.     subq.l    #1,d1        ;    = FAT size - 1
  1237.  
  1238. getb3:    move.w    sizr,d2        ; d2 = count per FAT sector
  1239.     subq.w    #1,d2
  1240.      clr.l    temp        ; initialize the sum
  1241. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1242.     move.l    a1,-(sp)    ; from sector a1
  1243.     move.w    cpun,-(sp)    ; physical unit
  1244.     addq.w    #2,(sp)        ; unit # including A: and B:
  1245.     move.w    #-1,-(sp)    ; using a long sector number
  1246.     move.w    #1,-(sp)    ; read 1 phys sector
  1247.     move.l    a0,-(sp)    ; buffer (in _dskbufp)
  1248.     move.w    #$a,-(sp)    ; read in physical mode/ignore media change
  1249.     bsr    _ahdi_rw    ; ahdi_rw($a, buf, 1, -1, cpun, lsecno)
  1250.     adda    #16,sp        ; clean up stack
  1251.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1252.     tst.w    d0        ; read successful?
  1253.     beq    getb5        ; if so, go on normally
  1254.                 ; else let user retry
  1255. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1256.     move.w    24(sp),d1    ; d1 = drive # excluding A: and B:
  1257.     bsr    critic        ; critical error handler
  1258.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1259.     cmpi.l    #CRITRETRY,d0    ; retry?
  1260.     beq.s    getb4        ; if so, try again
  1261.     bra    getb7        ; else return
  1262.  
  1263. getb5:    bsr    bsum        ; add up values in the sector
  1264.     addq    #1,a1        ; get ready for next sector
  1265.     dbra    d2,getb4    ; until one logical FAT sector is done
  1266.  
  1267.     bsr    csum        ; find the checksum
  1268.     move.b    d0,(a2)+    ; update checksum for this FAT sector
  1269.     dbra    d1,getb3    ; until all sectors are checked
  1270.  
  1271. getb6:    move.w    $4(sp),d0    ; d0 = dev number
  1272.     lea    mcflgs,a0    ; load address of mcflgs table
  1273.     clr.b    (a0,d0.w)    ; clear mcflg for dev
  1274.  
  1275.     lea    xst,a0        ; a0 -> drive existence table
  1276.     move.b    #2,(a0,d0.w)    ; dev definitely exists
  1277.  
  1278.     lea    fatst,a0    ; a0 -> FAT start sector table
  1279.     asl.w    #1,d0        ; offset = dev# * 2 (tbl of words)
  1280.     move    fatrec,(a0,d0.w); update FAT starting sect#
  1281.  
  1282.     lea    fatend,a0    ; a0 -> FAT end sector table
  1283.     move.w    fatrec,d1    ; d1 = fatend(dev)
  1284.     add.w    fsiz,d1        ;    = fatrec + fsiz - 1
  1285.     subq.w    #1,d1    
  1286.     move.w    d1,(a0,d0.w)    ; fatend(dev) = fatrec + fsiz - 1
  1287.  
  1288.     lea    partsize,a0    ; a0 -> end of partition table
  1289.     asl.w    #1,d0        ; offset = dev# * 2 * 2 (tbl of longs)
  1290.     clr.l    d1
  1291.     move.w    csize+2,d1    ; get number of sectors
  1292.     move.l    d1,0(a0,d0.w)    ; save size (in logical sectors) of device
  1293.  
  1294.     lea    start,a0    ; a0 -> beginning of start table
  1295.     move.l    $6(sp),(a0,d0.w); update starting sect# of dev
  1296.  
  1297.     move.l    #bpbs,d0    ; no errors, return ptr to BPB
  1298.     bra.s    getb8        ; return
  1299.  
  1300. getb7:    moveq    #-1,d0        ; error
  1301. getb8:    rts
  1302.  
  1303.  
  1304. ;+
  1305. ; WORD getlhw(d0=offset)
  1306. ; returns word (low,high) from 0(D0,A0)
  1307. ;-
  1308.     .globl    getlhw
  1309. getlhw:    move    d1,-(sp)    ; preserve d1
  1310.     move.b    1(a0,d0.w),d1
  1311.     lsl.w    #8,d1
  1312.     move.b    0(a0,d0.w),d1
  1313.     move    d1,d0
  1314.     move    (sp)+,d1
  1315.     rts
  1316.  
  1317.  
  1318. ;+
  1319. ; bsum
  1320. ;
  1321. ; Passed:
  1322. ;    a0 = starting address of buffer to be summed
  1323. ;    temp.l = current sum
  1324. ;
  1325. ; Function:
  1326. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1327. ;    - save the sum in temp.l
  1328. ;
  1329. ; Algorithm for check summing the FAT:
  1330. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1331. ;    - if the sum is non-zero, XOR the high word     (in csum)
  1332. ;      with the low word of the 4-byte result
  1333. ;    - now take this 2-byte result, and XOR its high    (in csum)
  1334. ;      byte with its low byte to get the final 1-byte
  1335. ;      result
  1336. ;-
  1337. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1338.     move.l    temp,d0            ; d0 = current sum
  1339.     move    #127,d1            ; count
  1340. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1341.     dbra    d1,bsum0        ; until all bytes are added
  1342.     move.l    d0,temp            ; temp.l = new sum
  1343.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1344.     rts
  1345.  
  1346.  
  1347. ;+
  1348. ; csum
  1349. ; (a) XOR the high word with the low word of temp.l
  1350. ; (b) then XOR the high byte with the low byte of result of (a)
  1351. ;
  1352. ; Returns:
  1353. ;    d0.b = checksum
  1354. ;-
  1355. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1356.     eor.w    d0,temp            ; exclusive-or low and high word
  1357.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1358.     eor.b    d0,temp            ; exclusive-or low and high byte
  1359.     move.b    temp,d0
  1360.     rts                ; d0.b = checksum
  1361.  
  1362.  
  1363. ;
  1364. ;+
  1365. ;  Read/Write sectors
  1366. ;
  1367. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1368. ;        WORD rw        4(sp).w        ; non-zero -> write
  1369. ;        char *buf    6(sp).l
  1370. ;        WORD count    $a(sp).w
  1371. ;        WORD recno    $c(sp).w
  1372. ;        WORD dev    $e(sp).w
  1373. ;        LONG lrecno    $10(sp).l    ; optional
  1374. ;-
  1375.  
  1376. ; stack frame offsets
  1377. xrw    equ    8
  1378. xbuf    equ    10
  1379. xcount    equ    14
  1380. xrecno    equ    16
  1381. xdev    equ    18
  1382. xlrecno    equ    20
  1383.  
  1384.     .globl    _sasi_rw
  1385.     .globl    _ahdi_rw
  1386. _sasi_rw:
  1387. _ahdi_rw:
  1388.     link    a6,#0            ; create a frame pointer
  1389.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1390.  
  1391.     move.w    xdev(a6),d0        ; d0 = device number
  1392.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1393.     beq.s    getcpun            ; if not, find physical unit number
  1394.     move.w    d0,cpun            ; else, dev# passed is phys unit #
  1395. ;+
  1396. ;  Aug-08-91    ml. The following line trashed the sizr set up
  1397. ;            by the logical mode rwabs() which calls the
  1398. ;            physical mode rwabs() recursively.
  1399. ;    move.w    #1,sizr            ; sector size ratio = 1
  1400. ;-
  1401.  
  1402.     bra    ahrw1            ; go start the r/w
  1403. getcpun:                ; map log -> phys unit number
  1404.     lea    pun,a0            ; a0 -> pun table
  1405.     move.b    (a0,d0.w),cpun+1    ; cpun = pun of dev
  1406.     
  1407.     lea    sratio,a0        ; a0 -> sector size ratio table
  1408.     move.b    (a0,d0.w),sizr+1    ; sizr = current sector size ratio
  1409.                     ;     (coerced to word)
  1410.     lea    partsize,a0        ; a0 -> partition size table
  1411.     move.w    d0,d1            ; d1 = drive #
  1412.     add.w    d1,d1            ; d1*2*2 (index into tbl of longs)
  1413.     add.w    d1,d1
  1414.     move.l    (a0,d1.w),csize        ; csize = dev size (in logical sectors)
  1415.     lea    start,a0
  1416.     move.l    (a0,d1.w),cstart    ; cstart = dev starting sector
  1417.  
  1418.     btst.b    #1,xrw+1(a6)        ; ignore media change?
  1419.     bne    ahrw1            ; if yes, go ahead and do r/w
  1420.                     ; else check for media change
  1421.     lea    mcflgs,a0        ; a0 -> mcflgs of drive
  1422.     move.b    (a0,d0.w),d0        ; d0 = mcflg of dev
  1423.     beq    ahrw1            ; if media not changed, go do r/w
  1424.  
  1425.     cmpi.b    #2,d0            ; is media definitely changed?
  1426.     beq    retmc            ; if yes, return media has changed
  1427.                     ; else, check if media has changed
  1428.                     ; try to read dev's boot sector
  1429. chkmc:    move.l    cstart,-(sp)        ; dev starting sector
  1430.     move.w    cpun,-(sp)        ; physical unit number
  1431.     addq.w    #2,(sp)            ; unit # including A: and B:
  1432.     move.w    #-1,-(sp)        ; using a long sector number
  1433.     move.w    #1,-(sp)        ; 1 sector
  1434.     move.l    _dskbufp,-(sp)        ; buffer
  1435.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1436.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1437.     adda    #16,sp            ; clean up stack
  1438.     tst.w    d0            ; read successful?
  1439.     beq.s    chkser            ; yes, go check serial number
  1440.  
  1441.     move.w    xdev(a6),d1        ; device number
  1442.     bsr    critic            ; call critical error handler
  1443.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1444.     beq.s    chkmc            ; if yes, go back and try it
  1445.     bra    ahrw7            ; else return
  1446.  
  1447. chkser:    lea    serno,a1        ; a1 -> serial #s table
  1448.     move.w    xdev(a6),d0        ; d0 = dev number
  1449.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1450.     adda.l    d0,a1            ; a1 -> serial # of dev
  1451.  
  1452.     move.l    _dskbufp,a2        ; a2 -> boot sector
  1453.     addq.w    #8,a2            ; a2 -> serial # in boot sector
  1454.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1455. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1456.     bne    ismc            ; if not, media has changed
  1457.     dbra    d0,cmpser        ; compare next byte of serial #
  1458.                     ; serial # hasn't changed, try FAT
  1459.     moveq    #0,d1            ; coerce to long
  1460.     move.w    xdev(a6),d1        ; d0 = dev number
  1461.     lea    fatsum,a1        ; a1 -> fat checksum table
  1462.     lsl.l    #FATLEN,d1        ; d1.w = index into table
  1463.     adda.l    d1,a1            ; a1 -> fat checksum of dev
  1464.  
  1465.     add.w    d0,d0            ; d0*2 = index into table of words
  1466.     lea    fatst,a2        ; a2 -> FAT start table
  1467.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1468.  
  1469.     lea    fatend,a2        ; a2 -> FAT end table
  1470.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1471.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1472.  
  1473.     movea.l    cstart,a2        ; a2 = start sector of dev
  1474.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1475.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1476.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1477.  
  1478.     movea.l    _dskbufp,a0        ; a0 -> dskbuf
  1479. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1480.     subq.w    #1,d2            ; d2 - 1 = counter
  1481.     clr.l    temp            ; initialize sum
  1482. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save d1, d2, a0, a1, a2
  1483.                     ; try to read this FAT sector
  1484.     move.l    a2,-(sp)        ; at sector a2
  1485.     move.w    cpun,-(sp)        ; physical unit number
  1486.     addq.w    #2,(sp)            ; unit # including A: and B:
  1487.     move.w    #-1,-(sp)        ; using a long sector number
  1488.     move.w    #1,-(sp)        ; 1 sector
  1489.     move.l    a0,-(sp)        ; buffer
  1490.     move.w    #$a,-(sp)        ; phys mode and no media change error
  1491.     bsr    _ahdi_rw        ; ahdi_rw($a, buf, 1, -1, cpun, sectno)
  1492.     adda    #16,sp            ; clean up stack
  1493.     movem.l    (sp)+,d1-d2/a0-a2    ; restore d1, d2, a0, a1, a2
  1494.     tst.w    d0            ; read successful?
  1495.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1496.                     ; else assume it's read error
  1497.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1498.     move.w    xdev(a6),d1        ; drive number
  1499.     bsr    critic
  1500.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1501.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1502.     beq.s    cfat0            ; if yes, go back and try it
  1503.     bra    ahrw7            ; else return
  1504.  
  1505. chkfat:    bsr    bsum            ; if ok, sum the sector
  1506.     addq    #1,a2            ; ready for try next sector
  1507.     dbra    d2,cfat0        ; until one FAT sector is summed
  1508.  
  1509.     bsr    csum            ; find the checksum
  1510.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1511.     bne    ismc            ; if not, media has changed
  1512.     dbra    d1,cmpfat        ; until all sectors are checked
  1513.  
  1514.     lea    mcflgs,a0        ; a0 -> mcflgs table
  1515.     adda.w    xdev(a6),a0        ; a0 -> mcflg of drive
  1516.     clr.b    (a0)            ; clear mcflg for dev
  1517.  
  1518. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1519.     beq    ahrw6            ; if =0, done
  1520.  
  1521.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1522.     bne.s    ahrw2            ; if not, we have a word record #
  1523.     movea.l    xlrecno(a6),a1        ; a1.l = start record #
  1524.     bra.s    ahrw3
  1525. ahrw2:    moveq    #0,d0            ; coerce to long
  1526.     move.w    xrecno(a6),d0        ; d0.l = recno
  1527.     movea.l    d0,a1            ; a1.l = start record #
  1528.  
  1529. ahrw3:    move.l    a1,strec        ; save first sector to r/w
  1530.     move.l    a1,d1            ; d1.l = starting sector to r/w
  1531.     moveq    #0,d2            ; coerce to long
  1532.     move.w    xcount(a6),d2        ; d2.l = #sectors to r/w
  1533.     adda.l    d2,a1            ; a1.l = last sector to r/w
  1534.     subq.l    #1,a1            ;      = first sector + count - 1
  1535.     move.l    a1,endrec        ; save last sector to r/w
  1536.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1537.  
  1538.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1539.     bne.s    ahrw4            ; if so, ready to r/w
  1540.                     ; else log -> phys sector mapping
  1541. ; Check for I/O past end of partition
  1542.     cmpa.l    csize,a1        ; a1 is last sector to read/write
  1543.     bcs    ahrwsok            ; if a1 < csize, everything is OK
  1544.     move.l    #ESEEK,d0        ; seek error
  1545.     bra    ahrw7
  1546. ahrwsok:
  1547.     mulu    sizr,d1            ; d1.l    = phys start sector to r/w
  1548.     add.l    cstart,d1        ;    = dev start sect + sect #
  1549.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1550.  
  1551. ahrw4:    move.w    xdev(a6),-(sp)        ; device # (excluding A: and B:)
  1552.     move.l    d1,-(sp)        ; starting sector
  1553.     move.l    d2,-(sp)        ; count (in sectors)
  1554.     move.l    xbuf(a6),-(sp)        ; buffer
  1555.     move.w    xrw(a6),-(sp)        ; read write flag
  1556.     bsr    _do_rw            ; do the read or write
  1557.     adda    #16,sp            ; clean up stack
  1558.     tst.l    d0            ; successful?
  1559.     beq.s    chkwr            ; if so, go on to wrap up
  1560.  
  1561.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1562.     bne    ahrw7            ; if not, give up
  1563.     btst.b    #3,xrw+1(a6)        ; is this a physical operation?
  1564.     bne    ahrw7            ; if so, return media change error
  1565.     bra    chkmc            ; and go check if media has changed 
  1566.                     ; check if wrote to boot sector
  1567. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1568.     btst    #0,d0            ; read or write?
  1569.     beq    ahrw6            ; if read, done
  1570.     btst.b    #6,cpun+1        ; is drive removable?
  1571.     beq    ahrw6            ; if not, done
  1572.     btst    #3,d0            ; was it a physical operation?
  1573.     bne    ahrw6            ; if it was, done
  1574.     tst.l    strec            ; wrote to boot sector?
  1575.     bne.s    wrfat            ; if not, check if wrote to FATs
  1576.     lea    mcflgs,a0        ; else, a0 -> mcflgs table
  1577.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1578.     move.b    #2,(a0)            ; assume medium has changed
  1579.                     ; check if wrote to FATs
  1580. wrfat:    lea    fatend,a0        ; a0 -> fatend table
  1581.     move.w    xdev(a6),d0        ; d0 = device number
  1582.     add.w    d0,d0            ; d0*2 = index into table of words
  1583.     moveq    #0,d1            ; coerce to long
  1584.     move.w    (a0,d0.w),d1        ; d1 = last sector of last FAT
  1585.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1586.     blt    ahrw6            ; if so, done
  1587.  
  1588.     lea    fatst,a0        ; a0 -> fatst table
  1589.     moveq    #0,d2            ; coerce to long
  1590.     move.w    (a0,d0.w),d2        ; d2 = first sector of last FAT
  1591.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1592.     bgt    ahrw6            ; if so, done
  1593.                     ; else update FAT sector checksums
  1594.     move.l    stbuf,a0        ; a0 -> buffer w/ written data
  1595.     lea    fatsum,a1        ; a1 -> start of fatsum table
  1596.     moveq    #0,d0            ; coerce to long
  1597.     move.w    xdev(a6),d0        ; d0 = dev number
  1598.     lsl.l    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1599.     adda.l    d0,a1            ; a1 -> dev's first FAT chksum
  1600.     move.l    strec,d0        ; d0 = first sector wrote to
  1601.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1602.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1603.                     ;     no adjustments needed
  1604.      blt.s    wrfat1            ; if strec < start(last FAT)
  1605.                     ;     begin from start(last FAT)
  1606.     move.l    strec,d2        ; else begin from strec
  1607.     adda.l    d0,a1            ; a1 -> fatsum to be updated
  1608.     bra.s    wrfat2
  1609.  
  1610. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1611.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1612.     add.l    d0,d0
  1613.     adda.l    d0,a0            ; a0 -> addr of buf for update
  1614.  
  1615. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1616.     ble.s    wrfat3            ;     stop at end(last FAT)
  1617.     move.l    endrec,d1        ; else stop at endrec
  1618.  
  1619. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1620. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1621.     subq.w    #1,d2            ; dbra likes one less
  1622.     clr.l    temp            ; initialize sum
  1623. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1624.     adda.l    #512,a0            ; point to next 512 bytes
  1625.     dbra    d2,wrfat5        ; until one logical sector is done
  1626.     bsr    csum            ; obtain checksum
  1627.     move.b    d0,(a1)+        ; record new fat checksum
  1628.     dbra    d1,wrfat4        ; do until all are updated
  1629.  
  1630. ahrw6:    clr.l    d0            ; got here with no errors!
  1631.     bra.s    ahrw7
  1632.  
  1633. ismc:    lea    mcflgs,a0        ; a0 -> mcflgs table
  1634.     adda.w    xdev(a6),a0        ; a0 -> dev's mcflg
  1635.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1636.     lea    xst,a0            ; a0 -> drive existence table
  1637.     adda.w    xdev(a6),a0        ; a0 -> xst flag of dev
  1638.     move.b    #2,(a0)            ; assume dev exists
  1639. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1640.  
  1641. ahrw7:    btst.b    #0,xrw+1(a6)        ; read or write?
  1642.     bne.s    ahrwd            ; if write, done
  1643.     tst.b    _cachexst        ; does a cache exist?
  1644.     beq.s    ahrwd            ; if not, done
  1645.                     ; else dump the cache
  1646.     move.l    d0,-(sp)        ; save the status
  1647.     move    sr,-(sp)        ; go to IPL 7
  1648.     ori    #$700,sr        ; no interrupts right now kudasai
  1649.     movecacrd0            ; d0 = (cache control register)
  1650.     ori.w    #$808,d0        ; dump both the D and I cache
  1651.     moved0cacr            ; update cache control register
  1652.     move    (sp)+,sr        ; restore interrupt state
  1653.     move.l    (sp)+,d0        ; restore the return value
  1654.  
  1655. ahrwd:    unlk    a6
  1656.     rts
  1657.  
  1658.  
  1659. ;+
  1660. ; smove() - Copy unaligned sectors (this is *supposed* to be slow!)
  1661. ;
  1662. ; Passed:
  1663. ;    d0 = # of sectors to be moved
  1664. ;    d1 = size of operation    (0 - byte; 2 - long;)
  1665. ;    a2 -> source buffer
  1666. ;    a1 -> dest buffer
  1667. ;
  1668. ; Trashes: d0, a1, a2
  1669. ;-
  1670. smove:    move.w    d1,-(sp)        ; save size of operation
  1671.     neg.w    d1            ; d0 = count
  1672.     addi.w    #9,d1            ;    = (# sectors * 512) >> op size
  1673.     asl.w    d1,d0            ;
  1674.     subq.w    #1,d0            ; dbra likes one less
  1675.     move.w    (sp)+,d1        ; restore operation size
  1676.     bne.s    smove2            ; if non-zero, use move longs
  1677.  
  1678. smove1:    move.b    (a2)+,(a1)+
  1679.     dbra    d0,smove1
  1680.     rts
  1681.  
  1682. smove2:    move.l    (a2)+,(a1)+
  1683.     dbra    d0,smove2
  1684.     rts
  1685.  
  1686.  
  1687. ;
  1688. ;+
  1689. ; _do_rw - called to read/write no more than 128K to an even boundary
  1690. ;
  1691. ; Passed:
  1692. ;    rw    4(sp).w        ; non-zero -> write
  1693. ;    buf    6(sp).l
  1694. ;    count    $a(sp).l    ; in # phys (512-byte) sectors
  1695. ;    recno    $e(sp).l    ; physical starting sector for r/w
  1696. ;    dev    $12(sp).w    ; log dev # exluding A: and B:
  1697. ;
  1698. ; Assumes:
  1699. ;    cpun = current physical unit to r/w
  1700. ;    if in logical mode, cstart = physical starting sector # of curr dev
  1701. ;
  1702. ; Mar-05-1990 ml.
  1703. ;    All I/O to ACSI and SCSI non-accessible memory will be done by
  1704. ; using the fast ram buffer (if there is one) or the diskbuf as an inter-
  1705. ; mediate stop for the transfer.
  1706. ;
  1707. ; Mar-07-1990 ml.
  1708. ;    Do not have to take care of cases when Rwabs() is supplied with
  1709. ; a buffer that would cross different kinds of memory.
  1710. ; ("It's deadly!" said AKP. :) )
  1711. ;
  1712. ; Aug-19-1991 ml.
  1713. ;    On the TT, ACSI accessible RAM upper limit is 10Mb instead of
  1714. ; 4Mb.
  1715. ;
  1716. ; ACSI accessible memory: (on ST)   $00000000 -> $003fffff
  1717. ;                    $ff000000 -> $ff3fffff
  1718. ;              (on TT)   $00000000 -> $009fffff
  1719. ;                    $ff000000 -> $ff9fffff
  1720. ; SCSI non-accessible memory
  1721. ; on the TT:                $c0000000 -> $fcffffff
  1722. ;                    $fe000000 -> $feffffff
  1723. ;-
  1724. yrw    equ    $8
  1725. ybuf    equ    $a
  1726. ycount    equ    $e
  1727. yrecno    equ    $12
  1728. ydev    equ    $16
  1729.  
  1730. ; Memory that ACSI _can_ DMA to
  1731. STDUAL    equ    $003fffff    ; upper limit of dual-purpose RAM on an ST
  1732. STCMPIH    equ    $ff3fffff    ; upper limit of compatible image on an ST
  1733. TTDUAL    equ    $009fffff    ; upper limit of dual-purpose RAM on a TT
  1734. TTCMPIH    equ    $ff9fffff    ; upper limit of compatible image on a TT
  1735. SPDUAL    equ    $00dfffff    ; upper limit of dual-purpose RAM on a Sparrow
  1736. SPCMPIH    equ    $ffdfffff    ; upper limit of compatible image on a Sparrow
  1737. CMPIL    equ    $ff000000    ; lower limit of compatible image for all
  1738.  
  1739. ; Memory that SCSI _cannot_ DMA to (non-DW)
  1740. A32D16L    equ    $c0000000    ; lower limit of A32:D16 Memory/Peripherals
  1741. A32D16H    equ    $fcffffff    ; upper limit of A32:D16 Memory/Peripherals 
  1742. VA24D16    equ    $fe000000    ; lower limit of VMEbus A24:D16
  1743. VA16D16    equ    $feffffff    ; upper limit of VMEbus    A16:D16
  1744.  
  1745. ; Cookies
  1746. _FRB    equ    $5f465242        ; _FRB
  1747.  
  1748. _do_rw:    link    a6,#0            ; create a frame pointer
  1749.     move.l    ycount(a6),d2        ; d2.l = # sectors requested to r/w
  1750.      movea.l    ybuf(a6),a1        ; a1.l = buffer addr to r/w
  1751.     btst.b    #4,cpun+1        ; talking IDE?
  1752.     bne    atrw0            ; if yes, go for it
  1753.     btst.b    #3,cpun+1        ; else talking SCSI?
  1754.     beq.s    acrw0            ; if not, talking ACSI
  1755.     tst.b    _spscsixst        ; if so, talking Sparrow SCSI?
  1756.     beq    scrw0            ; if not, it's regular SCSI
  1757.                     ; else, it's Sparrow SCSI
  1758.     cmp.l    #MAXSPSECTS,d2        ; more than one DMAful?
  1759.     bls.s    acrw1            ; if not, go check boundary
  1760.     move.l    #MAXSPSECTS,d2        ; else set count to r/w only 1 DMAful
  1761.     bra.s    acrw1
  1762.  
  1763. acrw0:    cmp.l    #MAXACSECTS,d2        ; more than one DMAful?
  1764.     bls.s    acrw1            ; if not, go check boundary
  1765.     move.l    #MAXACSECTS,d2        ; else set count to r/w only 1 DMAful
  1766. acrw1:    btst.b    #0,ybuf+3(a6)        ; buffer on odd boundary?
  1767.     bne.s    itrw0            ; if so, do intermediate transfer
  1768.  
  1769.     cmpi.l    #TT,machine        ; is driver running on a TT?
  1770.     bne.s    acrw2            ; if not, go on
  1771.                     ; else check against TT limits
  1772.     cmpa.l    #TTDUAL,a1        ; buf within ACSI accessible memory?
  1773.     bls    rw1            ; if so, go ahead with the I/O
  1774.     cmpa.l    #CMPIL,a1        ; else, do intermediate transfer
  1775.     bcs.s    itrw0
  1776.     cmpa.l    #TTCMPIH,a1
  1777.     bls    rw1
  1778.     bra    itrw0
  1779.     
  1780. acrw2:    cmpi.l    #SPARROW,machine    ; is driver running on a Sparrow?
  1781.     bne.s    acrw3            ; if not, assume it's an ST or STE
  1782.  
  1783.     cmpa.l    #SPDUAL,a1        ; buf within ACSI accessible memory?
  1784.     bls    rw1            ; if so, go ahead with the I/O
  1785.     cmpa.l    #CMPIL,a1        ; else, do intermediate transfer
  1786.     bcs.s    itrw0
  1787.     cmpa.l    #SPCMPIH,a1
  1788.     bls    rw1
  1789.     bra.s    itrw0
  1790.                     ; driver is running on ST or STE
  1791. acrw3:    cmpa.l    #STDUAL,a1        ; buf within ACSI accessible memory?
  1792.     bls    rw1            ; if so, go ahead with the I/O
  1793.     cmpa.l    #CMPIL,a1        ; else, do intermediate transfer
  1794.     bcs.s    itrw0
  1795.     cmpa.l    #STCMPIH,a1
  1796.     bls    rw1
  1797.                     ; doing intermediate transfer
  1798. itrw0:    moveq    #0,d1            ; assume moving 1 byte at a time
  1799.     btst.b    #0,ybuf+3(a6)        ; odd boundary?
  1800.     bne.s    itrw1            ; if so, assumption ok
  1801.     moveq    #2,d1            ; else move 1 long at a time
  1802.  
  1803. itrw1:    tst.l    frbbuf            ; is there a fast RAM buffer?
  1804.     bne.s    itrw2            ; if there is one, use it
  1805.                     ; else look for _FRB
  1806.     move.l    d1,-(sp)        ; save d1
  1807.     move.l    #frbbuf,-(sp)        ; pointer to fast RAM buffer
  1808.     move.l    #_FRB,-(sp)        ; looking for _FRB cookie
  1809.     bsr    _getcookie        ; 
  1810.     addq.w    #8,sp            ; clean up stack
  1811.     move.l    (sp)+,d1        ; restore d1
  1812.     tst.w    d0            ; found _FRB?
  1813.     bne.s    itrw2            ; if so, use it
  1814.                     ; else use dskbuf
  1815.     movea.l    _dskbufp,a1        ; a1 -> dskbuf
  1816.     cmpi.w    #2,d2            ; can only do 2 at a time tops
  1817.     bls.s    itrw3
  1818.     move.w    #2,d2
  1819.     bra.s    itrw3
  1820.  
  1821. itrw2:    movea.l    frbbuf,a1        ; use the Fast RAM Buffer
  1822.     cmpi.w    #RAMRSV,d2        ; can only do RAMRSV at a time tops
  1823.     bls.s    itrw3
  1824.     move.w    #RAMRSV,d2
  1825.  
  1826. itrw3:    btst.b    #0,yrw+1(a6)        ; is this a read?
  1827.     beq.s    rw1            ; if so, go fill buffer from disk
  1828.                     ; else fill buffer here
  1829.     move.l    a1,-(sp)        ; preserve a1 = dest
  1830.     movea.l    ybuf(a6),a2        ; a2 = source
  1831.     move.w    d2,d0            ; # sectors to be moved
  1832.     bsr    smove            ; move sectors from a2 to a1
  1833.     movea.l    (sp)+,a1        ; restore a1.l = dest
  1834.     bra.s    rw1            ; go do the r/w
  1835.  
  1836. scrw0:    cmpi.l    #MAXSCSECTS,d2        ; more than one SCSI DMAful?
  1837.     bls.s    scrw1            ; if not, ready to r/w
  1838.     move.l    #MAXSCSECTS,d2        ; r/w only one SCSI DMAful?
  1839.  
  1840. scrw1:    
  1841.  
  1842. .if    SCDMA                ; if doing SCSI DMA
  1843. .if    !SCFRDMA            ; if no SCSI DMA to fast RAM
  1844.     cmpi.b    #$01,ybuf(a6)        ; is destination buffer in fast RAM?
  1845.     beq    itrw0            ; if so, do intermediate transfer
  1846. .endif    ;!SCFRDMA
  1847.  
  1848.     cmpa.l    #A32D16L,a1        ; buf in SCSI non-accessible
  1849.     bcs.s    rw1            ;  memory?
  1850.     cmpa.l    #A32D16H,a1        ; if so, do intermediate transfer
  1851.     bls    itrw0            ; else, go ahead with the I/O
  1852.     cmpa.l    #VA24D16,a1
  1853.     bcs.s    rw1
  1854.     cmpa.l    #VA16D16,a1
  1855.     bls    itrw0
  1856. .endif    ;SCDMA
  1857.  
  1858.     bra.s    rw1
  1859.  
  1860. atrw0:    cmp.l    #MAXIDESECTS,d2        ; more than one IDE gulp?
  1861.     bls.s    atrw1            ; if not, check boundary
  1862.     move.l    #MAXIDESECTS,d2        ; else, r/w only one IDE gulp
  1863. atrw1:    btst.b    #0,ybuf+3(a6)        ; buffer on odd boundary?
  1864.     bne    itrw0            ; if so, do intermediate transfer
  1865.                     ; else ready for r/w
  1866. rw0:    movea.l    ybuf(a6),a1        ; a1 = buffer address for r/w
  1867. rw1:    move.w    _retries,retrycnt    ; setup retry counter
  1868.  
  1869.     btst.b    #2,yrw+1(a6)        ; are retries disabled?
  1870.     beq.s    rw2            ; no, act normally
  1871.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1872.  
  1873. rw2:    movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1874.     move.w    cpun,-(sp)        ; dev.w
  1875.     move.l    a1,-(sp)        ; buf.l
  1876.     move.w    d2,-(sp)        ; count.w
  1877.     move.l    yrecno(a6),-(sp)    ; sect.L
  1878.  
  1879.     btst.b    #4,cpun+1        ; talking IDE?
  1880.     bne.s    rwide            ; if so, do IDE r/w
  1881.                     ; else it's ACSI or SCSI
  1882.     cmpi.l    #MAXACSECTS,d2        ; more than hr/w can handle?
  1883.     bhi.s    rw4            ; if so, use extended call (SCSI only)
  1884.     btst.b    #0,yrw+1(a6)        ; read or write?
  1885.     bne.s    rw3            ; (write)
  1886.     bsr    _hread            ; read sectors
  1887.     bra    rw6
  1888. rw3:    bsr    _hwrite            ; write sectors
  1889.     bra.s    rw6
  1890. rw4:    btst.b    #0,yrw+1(a6)        ; read or write?
  1891.     bne.s    rw5            ; (write)
  1892.     bsr    _xtdread        ; read sectors
  1893.     bra.s    rw6
  1894. rw5:    bsr    _xtdwrt            ; write sectors
  1895.     bra.s    rw6
  1896.  
  1897. rwide:    lea    idedp,a0        ; a0 -> drive param structure
  1898.     move.w    2(a0),-(sp)        ; # physical sectors per track
  1899.     move.w    (a0),-(sp)        ; # data heads
  1900.     btst.b    #0,yrw+1(a6)        ; read or write?
  1901.     bne.s    rwide2            ; (write)
  1902.     bsr    _ideread        ; read sectors
  1903.     bra.s    rwide3
  1904. rwide2:    bsr    _idewrite        ; write sectors
  1905. rwide3:    addq    #4,sp            ; (cleanup stack)
  1906. rw6:    adda    #12,sp            ; (cleanup stack)
  1907.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1908.     tst.l    d0            ; errors?
  1909.     beq    rwf            ; no error --> successful
  1910.     bmi.s    rw9            ; timed out --> retry
  1911.  
  1912.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1913.     move.w    yrw(a6),-(sp)        ; rwflag
  1914.     bsr    errcode            ; find error code
  1915.     addq    #2,sp            ; clean up stack
  1916.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1917.  
  1918.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1919.     bne.s    rw7            ; if not, fine
  1920.                     ; else record media may be changed
  1921.     move.b    #1,d0            ; d0.b = 1 (may be changed)
  1922.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1923.  
  1924.     btst.b    #1,yrw+1(a6)        ; ignore media change?
  1925.     bne    rw2            ; if so, retry operation
  1926.     bra    rwr            ; else return
  1927.     
  1928. rw7:    cmpi.l    #EWRPRO,d0        ; write protect error?
  1929.     beq.s    rwa            ; if so, return error
  1930.     cmpi.l    #EDRVNR,d0        ; drive not ready?
  1931.     beq.s    rwa            ; if so, return error
  1932.  
  1933. rw9:    subq.w    #1,retrycnt        ; drop retry count and retry
  1934.     bpl    rw2
  1935.  
  1936. rwa:    btst.b    #3,yrw+1(a6)        ; is this a physical operation?
  1937.     bne    rwr            ; if so, exit
  1938.                     ; else call critical error handler
  1939.     movem.l    d1-d2/a1,-(sp)        ; preserve d1, d2 and a1
  1940.     move.w    ydev(a6),d1        ; d1 = drive number
  1941. rwe:    bsr    critic
  1942.     movem.l    (sp)+,d1-d2/a1        ; restore d1, d2 and a1
  1943.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1944.     beq    rw2            ; if yes, go retry
  1945.     bra.s    rwr            ; else, head home
  1946.  
  1947. rwf:    lea    rw0,a0            ; exec of next r/w starts at rw0
  1948.     cmpa.l    ybuf(a6),a1        ; was alternate buffer used?
  1949.     beq.s    rw10            ; if not, go on to next r/w
  1950.                     ; else take care of transfer
  1951.     lea    itrw3,a0        ; exec of next r/w starts at itrw3
  1952.     btst.b    #0,yrw+1(a6)        ; was it a write?
  1953.     bne.s    rw10            ; if it was, go on to next write
  1954.                     ; else move data to supplied buffer
  1955.     move.l    a1,-(sp)        ; save address of alternate buffer
  1956.     movea.l    a1,a2            ; a2 = address of alternate buffer
  1957.     movea.l    ybuf(a6),a1        ; a1 = address of supplied buffer
  1958.     move.w    d2,d0            ; d0 = # of sectors to move
  1959.     bsr    smove            ; move data from alt buf to sup buf
  1960.     move.l    (sp)+,a1        ; restore address of alternate buffer
  1961.  
  1962. rw10:    sub.l    d2,ycount(a6)        ; ycount(a6) = # sects left to be done
  1963.     beq.s    rwd            ; if no more left, done
  1964.                     ; else get ready for next r/w
  1965.     add.l    d2,yrecno(a6)        ; yrecno(a6) = next starting sector
  1966.     move.l    d2,d0            ; d0 = # bytes done
  1967.     asl.l    #8,d0            ;    = # sectors done * 512
  1968.     add.l    d0,d0            ; 
  1969.     add.l    d0,ybuf(a6)        ; buf += (sectors_done * sector size)
  1970.     cmp.l    ycount(a6),d2        ; amount to r/w > amount doable?
  1971.     bls.s    rw11            ; if so, r/w amount doable
  1972.     move.l    ycount(a6),d2        ; else r/w all of it
  1973. rw11:    jmp    (a0)            ; go on to next r/w
  1974.  
  1975. rwd:    moveq    #0,d0            ; got here with no errors!
  1976. rwr:    unlk    a6            ; head home
  1977.     rts
  1978.  
  1979.  
  1980. ;
  1981. ;+
  1982. ; Check for media change on hard disk
  1983. ; Synopsis:    _sasi_mediach(dev)
  1984. ;        WORD dev;        4(sp).w
  1985. ;
  1986. ; Returns:    0L - media definitely has not changed
  1987. ;        1L - media _may_ have changed
  1988. ;        2L - media definitely has changed
  1989. ;
  1990. ; Uses:        d0, d1, a0, a1
  1991. ;
  1992. ; Comments:
  1993. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1994. ;            If _sasi_mediach() was called less than 1 s
  1995. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1996. ;            not changed then, assume medium still has not 
  1997. ;            changed.
  1998. ;-
  1999. _sasi_mediach:
  2000.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  2001.     move.w    4(sp),d1        ; d1 = current drive
  2002.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  2003.     moveq    #0,d0            ; d0 = mcflg for current drive
  2004.     move.b    (a0,d1.w),d0    
  2005.     tst.b    d0            ; has medium changed?
  2006.     bne.s    decided            ; if yes or maybe, return result
  2007.                     ; else verify that it has not
  2008.     move.l    lastmdctm,d2        ; time media change was last called
  2009.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  2010.     bcc.s    decided            ;    assume medium not changed
  2011.  
  2012.     lea    pun,a1            ; ptr to beginning of pun table
  2013.     move.b    (a1,d1.w),cpun+1    ; cpun = pun current drive belongs to
  2014.  
  2015.     btst.b    #6,cpun+1        ; is pun removable?
  2016.     beq.s    notchngd        ; if not, medium has not changed
  2017.  
  2018.     move.w    cpun,-(sp)        ; physical unit number
  2019.     bsr    _untrdy            ; verify by doing test unit ready
  2020.     addq.l    #2,sp
  2021.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  2022.     addi.l    #200,lastmdctm        ; 
  2023.     tst.w    d0            ; return good status?
  2024.     beq.s    notchngd        ; if yes, return medium not changed
  2025.     moveq    #1,d0            ; else return medium may have changed
  2026.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  2027.     bra.s    decided
  2028. notchngd:
  2029.     moveq    #0,d0            ; return medium has not changed
  2030. decided:
  2031.     rts
  2032.  
  2033.  
  2034. ;+
  2035. ; s_mc_xst - set mcflgs and drive existence flags 
  2036. ;         for drives belonging to the current
  2037. ;         physical unit to value passed
  2038. ;
  2039. ; Passed:    d0.b - value to set to
  2040. ;-
  2041. s_mc_xst:
  2042.     movem.l    d1-d2/a0-a2,-(sp) ; save registers
  2043.     lea    pun,a0        ; a0 -> pun table
  2044.     lea    mcflgs,a1    ; a1 -> mcflgs table
  2045.     lea    xst,a2        ; a2 -> drive existence table
  2046.     move.w    cpun,d1        ; d1 = current physical unit #
  2047.     moveq    #0,d2        ; d2 = logical drive #; index into tables
  2048. set0:    btst.b    #7,(a0,d2.w)    ; a valid logical drive?
  2049.     bne.s    setr        ; if not, done
  2050.     cmp.b    (a0,d2.w),d1    ; else, does it belong to this physical unit?
  2051.     bne.s    set1        ; if not, move on to next logical drive
  2052.     move.b    d0,(a1,d2.w)    ; else change its mcflg to value passed
  2053.     move.b    d0,(a2,d2.w)    ; and change its xst to value passed
  2054. set1:    addq.w    #1,d2        ; try next one in forward direction
  2055.     cmp.w    #MAXLOG,d2    ; all units checked?
  2056.     blt.s    set0        ; if not, go on
  2057. setr:    movem.l    (sp)+,d1-d2/a0-a2 ; else restore registers
  2058.     rts            ; and return
  2059.  
  2060.  
  2061. ;
  2062. ;+
  2063. ; Resident Installer
  2064. ;-
  2065.     .globl    i_sasi6
  2066. i_sasi6:
  2067.     tst.b    idexst        ; IDE bus exists?
  2068.     beq.s    calcmem        ; if not, go calculate memory size
  2069.     cmpi.l    #SPARROW,machine    ; is driver running on a Sparrow?
  2070.     beq.s    calcmem
  2071. ;    move.b    #$10,d0        ; does IDE #0 exists?
  2072. ;    bsr    _drvxst
  2073. ;    beq.s    calcmem        ; if not, go calculate memory size
  2074.                 ; else
  2075.     move.w    ideidle,idesd    ; init current IDE spin down timeout
  2076.     beq.s    calcmem        ; if 0, don't set it
  2077.     move.w    ideidle,-(sp)    ; else set default time out
  2078.     move.w    #$10,-(sp)    ; IDE unit #0
  2079.     bsr    _awto        ; set up idle time out
  2080.     addq    #4,sp        ; clean up stack
  2081.  
  2082. ;+
  2083. ; 02-Apr-1991    ml.    The following is illegal, because i_sasi1 is 
  2084. ;            external.
  2085. ;    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  2086. ;-
  2087. calcmem:
  2088.     move.l    #i_sasi1,tokeep ; tokeep = amount of code to be kept
  2089.     subi.l    #i_sasi,tokeep
  2090.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  2091.     bls.s    nboot1        ; if not, no need to replace GEMDOS buffers
  2092.                 ; else check if there is enough memory for
  2093. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  2094.     tst.l    d0        ; enough?
  2095.     bpl.s    okbig        ; if so, build the list
  2096.     move.w    defbigsect,d0    ; d0 = minimum big sector
  2097.     cmp.w    maxssz,d0    ; is maxssz >= minimum big sector?
  2098.     bcc.s    regsect        ; if so, give up
  2099.     move.w    d0,maxssz    ; else try minimum big sector
  2100.     bra.s    chkmem
  2101. regsect:
  2102.     move.w    #512,maxssz    ; will not handle big sectors
  2103.     bra.s    nboot1
  2104.  
  2105. okbig:    move.l    d1,tokeep    ; update amount of memory to be kept
  2106.     lea    i_sasi1,a0    ; a0 -> beginning of new buffer lists
  2107.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  2108.     bsr    list_init    ; initialize the buffer list
  2109.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  2110.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  2111.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  2112.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  2113.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  2114.  
  2115. nboot1:    bsr    pool_install    ; attempt to install more OS pool
  2116.     add.l    d0,tokeep    ; update amount of memory to be kept
  2117.  
  2118. ;+
  2119. ; Aug-15-91    ml. Check for existence of _FRB when needed instead of
  2120. ;            at boot time.
  2121. ;
  2122. ;    clr.l    frbbuf        ; assume no _FRB
  2123. ;    move.l    #frbbuf,-(sp)    ; pointer to fast RAM buffer
  2124. ;    move.l    #$5f465242,-(sp)    ; cookie "_FRB"
  2125. ;    bsr    _getcookie    ; try to find _FRB in cookie jar
  2126. ;    addq.w    #8,sp        ; clean up stack
  2127. ;-
  2128.  
  2129.     move.l    _hz_200,lastmdctm   ; initialize media change time
  2130.     tst.w    bootloaded    ; if bootloaded, then already in super mode
  2131.     bne.s    nboot2        ; (already there)
  2132.     move.l    savssp,-(sp)    ; become a mild mannered user process
  2133.     move.w    #$20,-(sp)    ; Super(savssp)
  2134.     trap    #1
  2135.     addq.w    #6,sp
  2136.  
  2137. ;+
  2138. ; Terminate and stay resident;
  2139. ; installed driver under GEMDOS.
  2140. ;-
  2141.     move.l    tokeep,d0    ; compute value for Ptermres()
  2142.     add.l    #$0100,d0    ; for basepage
  2143.     move.l    d0,-(sp)    ; save D0
  2144.     movea.l    #msg_nbl,a0    ; print not bootloaded message
  2145.     bsr    prnstr
  2146.     move.l    (sp)+,d0
  2147.     move.w    #0,-(sp)    ; exit code
  2148.     move.l    d0,-(sp)
  2149.     move.w    #$31,-(sp)    ; terminate and stay resident
  2150.     trap    #1        ; should never come back...
  2151.     illegal
  2152.  
  2153.  
  2154. ;+
  2155. ;  Return to TOS ROMs
  2156. ;    - set default boot device to C:
  2157. ;    - Print silly message
  2158. ;    - Mshrink() memory that was alloc'd to us
  2159. ;    - set magic# in D7 for TOS ROMs
  2160. ;    - RTS back to ROMs
  2161. ;-
  2162. nboot2:    move.l    tokeep,d0    ; compute value for Mshrink
  2163.     add.l    #$1c,d0        ; for file header
  2164.     move.l    d0,-(sp)    ; save D0
  2165.     movea.l    #msg_bl,a0    ; print bootloaded message
  2166.     bsr    prnstr
  2167.  
  2168.     move.w    d4,d1        ; physical unit # in d4.w?
  2169.     bpl.s    bd0        ; if so, good
  2170.                 ; else it's in hi 3 bits of d7.b
  2171.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  2172.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  2173. bd0:    lea    pun,a0        ; a0 -> pun table
  2174.     moveq    #0,d2        ; d2 = boot dev
  2175. bd1:    move.b    (a0,d2.w),d0    ; d0.b = unit #
  2176.     andi.b    #$1f,d0        ; mask out flags
  2177.     cmp.b    d0,d1        ; d2 belongs to physical unit booted from?
  2178.     beq.s    bd2        ; if yes, set (d2) as boot device
  2179.     addq.w    #1,d2        ; else try next logical unit
  2180.     bra.s    bd1
  2181. bd2:    addq.w    #2,d2        ; offset for drive A and B
  2182.     move.w    d2,_bootdev    ; set default boot device to (d2)
  2183.  
  2184.     move.l    baseaddr,-(sp)
  2185.     clr.w    -(sp)
  2186.     move.w    #$4a,-(sp)    ; Mshrink(...)
  2187.     trap    #1
  2188.     adda    #12,sp        ; (cleanup stack)
  2189.  
  2190.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  2191.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  2192.     trap    #1
  2193.     addq.w    #4,sp        ; cleanup stack
  2194.  
  2195.     move.l    #rootpath,-(sp)    ; set root as current directory
  2196.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  2197.     trap    #1
  2198.     addq.w    #6,sp        ; cleanup stack
  2199. ;
  2200. ;    move.l    _sysbase,a0    ; get the system header address
  2201. ;    move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  2202. ;    swap    d0        ; d0.l = YYYYMMDD of ROM date
  2203. ;    cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  2204. ;    bcs.s    stopall        ; yup, if OS is built before 4/22/87
  2205. ;    move.b    puns+1,d7    ; else prevent processed units from booting
  2206. ;    subq.b    #1,d7        ; unit # = # of units - 1
  2207. ;    lsl.b    #5,d7
  2208. ;    rts            ; return to TOS ROMs
  2209. ;
  2210. ; Stop ANY subsequent boot after the hard disk boot -- FOR NOW!!
  2211. ;
  2212.  
  2213. stopall:
  2214.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  2215.     rts            ; return to TOS ROMs
  2216.  
  2217. rootpath:
  2218.     dc.b    '\\',0
  2219. msg_bl:
  2220.     dc.b    '-----------------------',13,10
  2221.     dc.b    'BOOTLOADED',13,10,0
  2222. msg_nbl:
  2223.     dc.b    '-----------------------',13,10
  2224.     dc.b    'NOT Bootloaded',13,10,0
  2225. .even
  2226.  
  2227.  
  2228. ;+
  2229. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  2230. ;
  2231. ; Passed:
  2232. ;     a0.l = head of buffer list            (not changed)
  2233. ;    d0.l = size of each BCB (including data block)    (not changed)
  2234. ;    d1.w = count
  2235. ;         = number of buffers to be installed to the list - 1
  2236. ;
  2237. ; Uses:
  2238. ;    d1, a1
  2239. ;-
  2240. list_init:
  2241.     move.l    a0,-(sp)    ; save head of buffer list
  2242. lin0:    movea.l    a0,a1        ; a1 -> next BCB
  2243.     adda.l    d0,a1        ;    -> curr BCB + size of BCB
  2244.     move.l    a1,(a0)        ; b_link -> next BCB
  2245.     move.w    #-1,4(a0)    ; b_neg1 = -1
  2246.     adda.w    #BCBLEN,a0    ; a0 -> BCB data block
  2247.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  2248.     movea.l    a1,a0
  2249.     dbra    d1,lin0
  2250.     suba.l    d0,a0        ; a0 -> last BCB
  2251.     clr.l    (a0)        ; lastBCB.b_link = NULL
  2252.     move.l    (sp)+,a0    ; restore head of buffer list
  2253.     rts
  2254.  
  2255.  
  2256. ;+
  2257. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  2258. ;        buffer lists
  2259. ;
  2260. ; Returns:
  2261. ;    d0.l = size of each BCB (including data block)
  2262. ;         or -1 if not enough memory is allocated
  2263. ;    d1.l = new amount of memory to be kept if enough is allocated
  2264. ;
  2265. ; Uses:
  2266. ;    d0, d1
  2267. ;-
  2268. chklstmem:
  2269.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  2270.     add.w    maxssz,d0    ;      = BCB header len + data block size
  2271.     move.l    d0,d1        ; d1.l = d0.l * 4 
  2272.     lsl.l    #2,d1        ;      = total size of buffer lists
  2273.     add.l    tokeep,d1    ; d1.l = size needed
  2274.     cmp.l    memalloc,d1    ; enough memory allocated?
  2275.     bls.s    chk0        ; if so return
  2276.     moveq    #-1,d0        ; else return error
  2277. chk0:    rts
  2278.  
  2279.  
  2280. ;
  2281. ;+
  2282. ; critic - call up the critical error handler.
  2283. ;
  2284. ; Passed:
  2285. ;    d0.w = error code
  2286. ;    d1.w = drive # excluding A: and B:
  2287. ;
  2288. ; Uses:
  2289. ;    d0, d1, a0
  2290. ;
  2291. ; Returns:
  2292. ;    d0.l = whatever returned by the critical handler
  2293. ;        (magic RETRY code or something)
  2294. ;-
  2295. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2296.     move.w    d1,-(sp)        ; drive #
  2297.     move.w    d0,-(sp)        ; error code
  2298.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2299.     jsr    (a0)            ; critic_handler(error, drive)
  2300.     addq.l    #4,sp            ; clean up stack
  2301.     rts                ; return
  2302.  
  2303.  
  2304. ;+
  2305. ; errcode - For ACSI or SCSI drives, find error code for previous 
  2306. ;        Check Condition Status, and translate controller error
  2307. ;        code into BIOS error code.
  2308. ;      - For IDE-IDE drives, test for error bits, and translate
  2309. ;        error bits into BIOS error code.
  2310. ;
  2311. ; Passed:
  2312. ;    d0.b    = value of Status register (IDE drive ONLY)
  2313. ;    4(sp).w    = rwflag (bit 0 not set -> read; bit 0 set -> write)
  2314. ;
  2315. ; Assumed:
  2316. ;    cpun = current physical unit number
  2317. ;
  2318. ; Returns:
  2319. ;    d0.l = BIOS error code
  2320. ;
  2321. ; Sep-13-1989    ml. For non-extended request sense, ask for 0 byte.
  2322. ;            (0 is default to return 4 bytes.)
  2323. ; Aug-19-1991    ml. Moved translation of controller error code into
  2324. ;            BIOS error code from _ahdi_rw() to here.
  2325. ;-
  2326.     .globl    errcode
  2327. errcode:
  2328.     btst.b    #4,cpun+1        ; an IDE unit?
  2329.     bne.s    ideerr            ; if so, handle it the IDE way
  2330.                     ; else it's ACSI or SCSI
  2331.     moveq    #22,d1            ; assume requesting extended sense
  2332.     move.w    cpun,d0            ; d0 = physical unit number
  2333.     btst    #3,d0            ; a SCSI unit?
  2334.     bne.s    err0            ; if so, ready to request
  2335.     andi.w    #07,d0            ; else mask off other flags
  2336.     btst.b    d0,embscsi        ; an embedded SCSI unit using ACSI?
  2337.     bne.s    err0            ; if so, request extended sense
  2338.     moveq    #0,d1            ; else request non-extended sense
  2339. err0:    lea    sendata,a0        ; a0 -> sense data buffer
  2340.     movem.l    d1/a0,-(sp)        ; save data len and buffer address
  2341.     move.l    a0,-(sp)        ; sense data buffer
  2342.     move.w    d1,-(sp)        ; data length (in bytes)
  2343.     move.w    d0,-(sp)        ; physical unit number
  2344.     bsr    _rqsense        ; find out error code
  2345.     addq.l    #8,sp            ; clean up stack
  2346.     movem.l    (sp)+,d1/a0        ; restore d1 and a0
  2347.     tst.w    d0            ; successful?
  2348.     beq.s    err1            ; if not, return
  2349.     moveq    #-1,d0            ; error occurred
  2350.     rts
  2351. err1:    cmpi.w    #4,d1            ; extended or non-extended?
  2352.     bgt.s    err2            ; if extended, go get code
  2353.     move.b    (a0),d1            ; else byte 0 = error code
  2354.     andi.b    #$7f,d1            ; mask off valid bit
  2355.     bra.s    err3
  2356. err2:    move.b    12(a0),d1        ; else byte 12 = error code
  2357.  
  2358. err3:    cmpi.b    #MDMCHGD,d1        ; is it media change detected?
  2359.     bne.s    err4            ; if not, check further
  2360.     move.l    #E_CHNG,d0        ; else return media change error
  2361.     bra.s    errend
  2362.  
  2363. err4:    cmpi.b    #WRTPRTD,d1        ; is it write protect error?
  2364.     bne.s    err5            ; if not, check further
  2365.     move.l    #EWRPRO,d0        ; else return write protect error
  2366.     bra.s    errend
  2367.  
  2368. err5:    cmpi.b    #DRVNRDY,d1        ; is it drive not ready?
  2369.     bne.s    err7            ; if not, assume read or write fault
  2370. err6:    move.l    #EDRVNR,d0        ; else return drive not ready error
  2371.     bra.s    errend
  2372.  
  2373. err7:    btst.b    #0,5(sp)        ; read or write?
  2374.     bne.s    errw            ; (write)
  2375.     move.l    #EREADF,d0        ; return read fault
  2376.     bra.s    errend
  2377.  
  2378. ideerr:    btst    #DRDY,d0        ; is IDE drive not ready?
  2379.     beq.s    err6            ; if so, return drive not ready
  2380.  
  2381.     btst    #DWF,d0            ; is it write fault error?
  2382.     bne.s    err7            ; if not, assume read or write fault
  2383. errw:    move.l    #EWRITF,d0        ; else return write fault error
  2384. errend:    rts
  2385.  
  2386.  
  2387.  
  2388.  
  2389. ;
  2390. ;+
  2391. ; OS Pool Expansion
  2392. ;-
  2393.  
  2394. .if ospool
  2395. ;+
  2396. ;  Wire more pool into various ROM releases.
  2397. ;
  2398. ;    Passed:    nothing
  2399. ;    Returns:    D0 = #bytes extra used
  2400. ;-
  2401. pool_install:
  2402.     move.l    _sysbase,a3        ; a3 -> base of OS
  2403.  
  2404. ; make sure we're in ROM,
  2405. ; then get address of RAM location to patch:
  2406.  
  2407.     cmp.l    #$800000,a3        ; better be ROM
  2408.     blt    notrom
  2409.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2410. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2411.     beq    badrom            ; (forget it, end of list)
  2412.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2413.     cmp.l    $18(a3),d1        ; match dates?
  2414.     bne.s    pi_lp            ; (no -- try again)
  2415.  
  2416.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2417.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2418.     move.l    d0,d1            ; d1 = total memory needed
  2419.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2420.     cmp.l    memalloc,d1        ; enough is allocated?
  2421.     bgt.s    bdrom2            ; if not, don't add any
  2422.                     ; else install more OS pool
  2423.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2424.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2425.     move.l    a0,-(sp)        ; save base of first buffer
  2426.     move.w    numchunks,d1        ; d0 = count-1
  2427.     subq.w    #1,d1
  2428. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2429.     move.l    a1,(a0)            ; buffer -> next one
  2430.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2431.     move.l    a1,a0            ; a0 -> next buffer
  2432.     dbra    d1,pin_1        ; (do some more)
  2433.  
  2434.     sub.w    #chunksiz,a0        ; a0 -> last block
  2435.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2436.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2437.     rts                ; return OK
  2438.  
  2439. ;+
  2440. ;  Print warning messages
  2441. ;  about bogus versions of the
  2442. ;  operating system.  Assume that
  2443. ;  every OS past 1-May-1986 has the
  2444. ;  pool fix installed.
  2445. ;
  2446. ;-
  2447. ok_date    =    %0000110010100001    ; 1-May-1986
  2448. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2449.     bra.s    bdrom1
  2450. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2451. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2452.     bcc    bdrom2            ; then don't print anything
  2453.  
  2454.     move.l    a0,-(sp)        ; print nasty message
  2455.     move.w    #9,-(sp)
  2456.     trap    #1
  2457.     addq.l    #6,sp
  2458.  
  2459. ; print msg and wait for RETURN
  2460.     pea    keymsg(pc)
  2461.     move.w    #9,-(sp)
  2462.     trap    #1
  2463.     addq.l    #6,sp
  2464.  
  2465. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2466.     move.w    #2,-(sp)
  2467.     trap    #13
  2468.     addq.l    #4,sp
  2469.     cmp.w    #13,d0
  2470.     bne    bdrom3
  2471.  
  2472. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2473.     rts
  2474.  
  2475. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2476.     dc.b    'key to continue:',13,10
  2477.     dc.b    0
  2478.  
  2479. m_notrom:
  2480.     dc.b    '*** WARNING ***',13,10,7
  2481.     dc.b    'This hard disk driver may not work with',13,10,7
  2482.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2483.     dc.b    'your hard disk may be damaged.',13,10,7
  2484.     dc.b    13,10,7
  2485.     dc.b    0
  2486.  
  2487. m_badrom:
  2488.     dc.b    '*** WARNING ***',13,10,7
  2489.     dc.b    'You are using an unofficial ROM release',13,10,7
  2490.     dc.b    'of the operating system.  This driver',13,10,7
  2491.     dc.b    'may not work correctly with it.  Files',13,10,7
  2492.     dc.b    'on your hard disk may be damaged.',13,10,7
  2493.     dc.b    13,10,7
  2494.     dc.b    0
  2495.     even
  2496.  
  2497.  
  2498. ;+
  2499. ;  Table of ROM release dates / _root addresses
  2500. ;  update these for new ROM releases that need the patch.
  2501. ;
  2502. ;-
  2503. pool_tab:
  2504.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2505.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2506.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2507.     dc.l    0            ; end of list
  2508.  
  2509. .endif
  2510.  
  2511.  
  2512.